Merge master.kernel.org:/pub/scm/linux/kernel/git/sfrench/cifs-2.6
This commit is contained in:
commit
fca324e79f
27 changed files with 2445 additions and 725 deletions
|
@ -32,6 +32,10 @@ Domen Puncer
|
|||
Jesper Juhl (in particular for lots of whitespace/formatting cleanup)
|
||||
Vince Negri and Dave Stahl (for finding an important caching bug)
|
||||
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
|
||||
-------------------------------------
|
||||
|
|
|
@ -1,8 +1,52 @@
|
|||
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
|
||||
------------
|
||||
Add writepage performance improvements. Fix path name conversions
|
||||
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
|
||||
------------
|
||||
|
@ -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
|
||||
recommended, unmount and rmmod cifs will kill them when they are
|
||||
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
|
||||
off in the page cache.
|
||||
|
||||
|
@ -101,7 +145,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call.
|
|||
|
||||
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
|
||||
for readdir to netapp servers. Fix search rewind (seek into readdir to return
|
||||
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
|
|||
page cache could contain stale data, and write through did
|
||||
not occur often enough while file was still open when read ahead
|
||||
(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.
|
||||
|
||||
Version 1.01
|
||||
|
@ -286,7 +330,7 @@ Allow passwords longer than 16 bytes. Allow null password string.
|
|||
Version 1.00
|
||||
------------
|
||||
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.
|
||||
|
||||
Version 0.99
|
||||
|
@ -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
|
||||
copy rather than later modified server copy of file. Do not reconnect
|
||||
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.
|
||||
|
||||
Version 0.98
|
||||
|
@ -637,7 +681,7 @@ versions of 2.4 kernel (now builds and works again on kernels at least as early
|
|||
Version 0.41
|
||||
------------
|
||||
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
|
||||
------------
|
||||
|
@ -704,7 +748,7 @@ session)
|
|||
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
|
||||
(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
|
||||
|
||||
8) Started adding the readlink and follow_link code
|
||||
|
|
|
@ -294,8 +294,10 @@ A partial list of the supported mount options follows:
|
|||
during the local client kernel build will be used.
|
||||
If server does not support Unicode, this parameter is
|
||||
unused.
|
||||
rsize default read size
|
||||
wsize default write size
|
||||
rsize default read size (usually 16K)
|
||||
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
|
||||
server may still consider the share read-only)
|
||||
ro mount network share read-only
|
||||
|
@ -407,6 +409,13 @@ A partial list of the supported mount options follows:
|
|||
This has no effect if the server does not support
|
||||
Unicode on the wire.
|
||||
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
|
||||
or vice versa)
|
||||
|
||||
|
@ -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
|
||||
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
|
||||
|
||||
|
|
50
fs/cifs/TODO
50
fs/cifs/TODO
|
@ -1,4 +1,4 @@
|
|||
version 1.34 April 29, 2005
|
||||
version 1.37 October 9, 2005
|
||||
|
||||
A Partial List of Missing Features
|
||||
==================================
|
||||
|
@ -7,15 +7,15 @@ Contributions are welcome. There are plenty of opportunities
|
|||
for visible, important contributions to this module. Here
|
||||
is a partial list of the known problems and missing features:
|
||||
|
||||
a) Support for SecurityDescriptors for chmod/chgrp/chown so
|
||||
these can be supported for Windows servers
|
||||
a) Support for SecurityDescriptors(Windows/CIFS ACLs) for chmod/chgrp/chown
|
||||
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
|
||||
SecurityDescriptors
|
||||
|
||||
c) Better pam/winbind integration (e.g. to handle uid mapping
|
||||
better)
|
||||
|
||||
c) multi-user mounts - multiplexed sessionsetups over single vc
|
||||
(ie tcp session) - more testing needed
|
||||
|
||||
d) Kerberos/SPNEGO session setup support - (started)
|
||||
|
||||
e) NTLMv2 authentication (mostly implemented)
|
||||
|
@ -29,12 +29,17 @@ f) Directory entry caching relies on a 1 second timer, rather than
|
|||
using FindNotify or equivalent. - (started)
|
||||
|
||||
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
|
||||
performance) and syncpage
|
||||
i) quota support (needs minor kernel change since quota calls
|
||||
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
|
||||
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
|
|||
in the Extended Attribute format their SFU clients would recognize.
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
exists. This is helpful when Unix extensions are negotiated to
|
||||
allow better permission checking when UIDs differ on the server
|
||||
|
@ -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
|
||||
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)
|
||||
====================================
|
||||
See http://bugzilla.samba.org - search on product "CifsVFS" for
|
||||
|
|
|
@ -191,7 +191,8 @@ asn1_header_decode(struct asn1_ctx *ctx,
|
|||
unsigned char **eoc,
|
||||
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))
|
||||
return 0;
|
||||
|
|
|
@ -81,6 +81,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
|
|||
buf += length;
|
||||
length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION);
|
||||
buf += length;
|
||||
length = sprintf(buf,"Active VFS Requests: %d\n", GlobalTotalActiveXid);
|
||||
buf += length;
|
||||
length = sprintf(buf, "Servers:");
|
||||
buf += length;
|
||||
|
||||
|
@ -97,7 +99,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
|
|||
} else {
|
||||
length =
|
||||
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,
|
||||
atomic_read(&ses->inUse),
|
||||
ses->serverOS, ses->serverNOS,
|
||||
|
@ -105,12 +107,18 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
|
|||
buf += length;
|
||||
}
|
||||
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,
|
||||
atomic_read(&ses->server->socketUseCount),
|
||||
ses->server->secMode,
|
||||
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");
|
||||
buf += length;
|
||||
|
||||
|
@ -149,7 +157,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
|
|||
dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
|
||||
length =
|
||||
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,
|
||||
atomic_read(&tcon->useCount),
|
||||
tcon->nativeFileSystem,
|
||||
|
@ -195,6 +203,49 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
|
|||
}
|
||||
|
||||
#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
|
||||
cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
|
||||
int count, int *eof, void *data)
|
||||
|
@ -254,35 +305,51 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
|
|||
buf += sprintf(buf, "\tDISCONNECTED ");
|
||||
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_oplock_brks));
|
||||
buf += 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),
|
||||
(long long)(tcon->bytes_read));
|
||||
buf += 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),
|
||||
(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;
|
||||
length += item_length;
|
||||
item_length = sprintf(buf,
|
||||
"\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d",
|
||||
atomic_read(&tcon->num_opens),
|
||||
atomic_read(&tcon->num_deletes),
|
||||
item_length = sprintf(buf, "\nMkdirs: %d Rmdirs: %d",
|
||||
atomic_read(&tcon->num_mkdirs),
|
||||
atomic_read(&tcon->num_rmdirs));
|
||||
buf += item_length;
|
||||
length += item_length;
|
||||
item_length = sprintf(buf,
|
||||
"\nRenames: %d T2 Renames %d",
|
||||
item_length = sprintf(buf, "\nRenames: %d T2 Renames %d",
|
||||
atomic_read(&tcon->num_renames),
|
||||
atomic_read(&tcon->num_t2renames));
|
||||
buf += 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);
|
||||
|
||||
|
@ -341,8 +408,10 @@ cifs_proc_init(void)
|
|||
cifs_debug_data_read, NULL);
|
||||
|
||||
#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);
|
||||
if (pde)
|
||||
pde->write_proc = cifs_stats_write;
|
||||
#endif
|
||||
pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs,
|
||||
cifsFYI_read, NULL);
|
||||
|
@ -360,7 +429,7 @@ cifs_proc_init(void)
|
|||
if (pde)
|
||||
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);
|
||||
if (pde)
|
||||
pde->write_proc = quotaEnabled_write;
|
||||
|
@ -419,7 +488,7 @@ cifs_proc_clean(void)
|
|||
remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
|
||||
remove_proc_entry("PacketSigningEnabled",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("cifs", proc_root_fs);
|
||||
}
|
||||
|
@ -459,6 +528,8 @@ cifsFYI_write(struct file *file, const char __user *buffer,
|
|||
cifsFYI = 0;
|
||||
else if (c == '1' || c == 'y' || c == 'Y')
|
||||
cifsFYI = 1;
|
||||
else if((c > '1') && (c <= '9'))
|
||||
cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
void cifs_dump_mem(char *label, void *data, int length);
|
||||
extern int traceSMB; /* flag which enables the function below */
|
||||
void dump_smb(struct smb_hdr *, int);
|
||||
#define CIFS_INFO 0x01
|
||||
#define CIFS_RC 0x02
|
||||
#define CIFS_TIMER 0x04
|
||||
|
||||
/*
|
||||
* debug ON
|
||||
|
@ -36,7 +39,7 @@ void dump_smb(struct smb_hdr *, int);
|
|||
|
||||
/* information message: e.g., configuration, major event */
|
||||
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
|
||||
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
#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_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 cifsTconInfo *tcon; /* primary mount */
|
||||
|
|
|
@ -59,6 +59,8 @@ unsigned int ntlmv2_support = 0;
|
|||
unsigned int sign_CIFS_PDUs = 1;
|
||||
extern struct task_struct * oplockThread; /* remove sparse warning */
|
||||
struct task_struct * oplockThread = NULL;
|
||||
extern struct task_struct * dnotifyThread; /* remove sparse warning */
|
||||
struct task_struct * dnotifyThread = NULL;
|
||||
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
|
||||
module_param(CIFSMaxBufSize, int, 0);
|
||||
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);
|
|||
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_dnotify_exited);
|
||||
|
||||
extern mempool_t *cifs_sm_req_poolp;
|
||||
extern mempool_t *cifs_req_poolp;
|
||||
|
@ -202,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf)
|
|||
#endif /* CIFS_EXPERIMENTAL */
|
||||
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;
|
||||
__fsid_t f_fsid;
|
||||
|
@ -253,7 +260,7 @@ cifs_alloc_inode(struct super_block *sb)
|
|||
cifs_inode->clientCanCacheAll = FALSE;
|
||||
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_flags = S_NOATIME | S_NOCMTIME;
|
||||
INIT_LIST_HEAD(&cifs_inode->openFileList);
|
||||
return &cifs_inode->vfs_inode;
|
||||
}
|
||||
|
@ -398,6 +405,34 @@ static struct quotactl_ops cifs_quotactl_ops = {
|
|||
};
|
||||
#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)
|
||||
{
|
||||
*flags |= MS_NODIRATIME;
|
||||
|
@ -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
|
||||
us with the same number of releases (closes) as opens */
|
||||
.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,
|
||||
};
|
||||
|
||||
|
@ -783,9 +818,7 @@ static int cifs_oplock_thread(void * dummyarg)
|
|||
do {
|
||||
if (try_to_freeze())
|
||||
continue;
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
schedule_timeout(1*HZ);
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if(list_empty(&GlobalOplock_Q)) {
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
|
@ -834,10 +867,27 @@ static int cifs_oplock_thread(void * dummyarg)
|
|||
}
|
||||
} else
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule_timeout(1); /* yield in case q were corrupt */
|
||||
}
|
||||
} while(!signal_pending(current));
|
||||
complete_and_exit (&cifs_oplock_exited, 0);
|
||||
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
|
||||
|
@ -851,6 +901,10 @@ init_cifs(void)
|
|||
INIT_LIST_HEAD(&GlobalSMBSessionList);
|
||||
INIT_LIST_HEAD(&GlobalTreeConnectionList);
|
||||
INIT_LIST_HEAD(&GlobalOplock_Q);
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
INIT_LIST_HEAD(&GlobalDnotifyReqList);
|
||||
INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
|
||||
#endif
|
||||
/*
|
||||
* Initialize Global counters
|
||||
*/
|
||||
|
@ -886,10 +940,16 @@ init_cifs(void)
|
|||
if (!rc) {
|
||||
rc = (int)kernel_thread(cifs_oplock_thread, NULL,
|
||||
CLONE_FS | CLONE_FILES | CLONE_VM);
|
||||
if(rc > 0)
|
||||
return 0;
|
||||
else
|
||||
if(rc > 0) {
|
||||
rc = (int)kernel_thread(cifs_dnotify_thread, NULL,
|
||||
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));
|
||||
}
|
||||
}
|
||||
cifs_destroy_request_bufs();
|
||||
}
|
||||
|
@ -918,6 +978,10 @@ exit_cifs(void)
|
|||
send_sig(SIGTERM, oplockThread, 1);
|
||||
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>");
|
||||
|
|
|
@ -81,6 +81,7 @@ extern int cifs_dir_notify(struct file *, unsigned long arg);
|
|||
|
||||
/* Functions related to dir entries */
|
||||
extern struct dentry_operations cifs_dentry_ops;
|
||||
extern struct dentry_operations cifs_ci_dentry_ops;
|
||||
|
||||
/* Functions related to symlinks */
|
||||
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);
|
|||
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
|
||||
extern int cifs_ioctl (struct inode * inode, struct file * filep,
|
||||
unsigned int command, unsigned long arg);
|
||||
#define CIFS_VERSION "1.35"
|
||||
#define CIFS_VERSION "1.39"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
|
|
@ -110,8 +110,9 @@ enum protocolEnum {
|
|||
*/
|
||||
|
||||
struct TCP_Server_Info {
|
||||
char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */
|
||||
char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */
|
||||
/* 15 character server name + 0x20 16th byte indicating type = srv */
|
||||
char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
|
||||
char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
|
||||
struct socket *ssocket;
|
||||
union {
|
||||
struct sockaddr_in sockAddr;
|
||||
|
@ -122,13 +123,17 @@ struct TCP_Server_Info {
|
|||
struct list_head pending_mid_q;
|
||||
void *Server_NlsInfo; /* BB - placeholder for future NLS info */
|
||||
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;
|
||||
char versionMajor;
|
||||
char versionMinor;
|
||||
unsigned svlocal:1; /* local server or remote */
|
||||
atomic_t socketUseCount; /* number of open cifs sessions on socket */
|
||||
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 */
|
||||
struct semaphore tcpSem;
|
||||
struct task_struct *tsk;
|
||||
|
@ -147,8 +152,10 @@ struct TCP_Server_Info {
|
|||
/* (returned on Negotiate */
|
||||
int capabilities; /* allow selective disabling of caps by smb sess */
|
||||
__u16 timeZone;
|
||||
__u16 CurrentMid; /* multiplex id - rotating counter */
|
||||
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 */
|
||||
char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];
|
||||
};
|
||||
|
@ -214,19 +221,41 @@ struct cifsTconInfo {
|
|||
atomic_t num_reads;
|
||||
atomic_t num_oplock_brks;
|
||||
atomic_t num_opens;
|
||||
atomic_t num_closes;
|
||||
atomic_t num_deletes;
|
||||
atomic_t num_mkdirs;
|
||||
atomic_t num_rmdirs;
|
||||
atomic_t num_renames;
|
||||
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_written;
|
||||
spinlock_t stat_lock;
|
||||
#endif
|
||||
#endif /* CONFIG_CIFS_STATS */
|
||||
FILE_SYSTEM_DEVICE_INFO fsDevInfo;
|
||||
FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */
|
||||
FILE_SYSTEM_UNIX_INFO fsUnixInfo;
|
||||
unsigned retry:1;
|
||||
unsigned nocase:1;
|
||||
/* BB add field for back pointer to sb struct? */
|
||||
};
|
||||
|
||||
|
@ -270,6 +299,7 @@ struct cifsFileInfo {
|
|||
struct inode * pInode; /* needed for oplock break */
|
||||
unsigned closePend:1; /* file is marked to close */
|
||||
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*/
|
||||
char * search_resume_name; /* BB removeme BB */
|
||||
unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */
|
||||
|
@ -306,6 +336,41 @@ CIFS_SB(struct super_block *sb)
|
|||
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 */
|
||||
struct mid_q_entry {
|
||||
|
@ -313,7 +378,11 @@ struct mid_q_entry {
|
|||
__u16 mid; /* multiplex id */
|
||||
__u16 pid; /* process id */
|
||||
__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 task_struct *tsk; /* task waiting for response */
|
||||
struct smb_hdr *resp_buf; /* response buffer */
|
||||
|
@ -331,6 +400,20 @@ struct oplock_q_entry {
|
|||
__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_REQUEST_ALLOCATED 1
|
||||
#define MID_REQUEST_SUBMITTED 2
|
||||
|
@ -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 GlobalDnotifyReqList; /* Outstanding dir notify requests */
|
||||
GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */
|
||||
|
||||
/*
|
||||
* Global transaction id (XID) information
|
||||
*/
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -47,19 +47,24 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
|
|||
struct smb_hdr * /* input */ ,
|
||||
struct smb_hdr * /* out */ ,
|
||||
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 checkSMB(struct smb_hdr *smb, __u16 mid, int length);
|
||||
extern int is_valid_oplock_break(struct smb_hdr *smb);
|
||||
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_LE(struct smb_hdr *ptr);
|
||||
extern int decode_negTokenInit(unsigned char *security_blob, int length,
|
||||
enum securityEnum *secType);
|
||||
extern int cifs_inet_pton(int, char * source, void *dst);
|
||||
extern int map_smb_to_linux_error(struct smb_hdr *smb);
|
||||
extern void header_assemble(struct smb_hdr *, char /* command */ ,
|
||||
const struct cifsTconInfo *, int /* specifies length
|
||||
of fixed section (word count) in two byte units */
|
||||
);
|
||||
const struct cifsTconInfo *, int /* length of
|
||||
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,
|
||||
struct cifsTconInfo *);
|
||||
extern void DeleteOplockQEntry(struct oplock_q_entry *);
|
||||
|
@ -89,7 +94,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
|
|||
|
||||
extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
|
||||
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,
|
||||
__u16 searchHandle, struct cifs_search_info * psrch_inf);
|
||||
|
@ -101,6 +106,10 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
|
|||
const unsigned char *searchName,
|
||||
FILE_ALL_INFO * findData,
|
||||
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,
|
||||
struct cifsTconInfo *tcon,
|
||||
|
@ -125,6 +134,11 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
|
|||
int remap);
|
||||
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
|
||||
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,
|
||||
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,
|
|||
const int access_flags, const int omode,
|
||||
__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
|
||||
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,
|
||||
const int smb_file_id);
|
||||
|
||||
|
@ -222,7 +241,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
|
|||
extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
|
||||
const int netfid, const unsigned int count,
|
||||
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,
|
||||
const unsigned char *searchName, __u64 * inode_number,
|
||||
const struct nls_table *nls_codepage,
|
||||
|
@ -264,7 +283,8 @@ extern int CIFSSMBCopy(int xid,
|
|||
int remap_special_chars);
|
||||
extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
|
||||
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,
|
||||
const unsigned char *searchName, char * EAData,
|
||||
size_t bufsize, const struct nls_table *nls_codepage,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,6 +29,8 @@
|
|||
#include <linux/utsname.h>
|
||||
#include <linux/mempool.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/pagevec.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/processor.h>
|
||||
#include "cifspdu.h"
|
||||
|
@ -44,6 +46,8 @@
|
|||
#define CIFS_PORT 445
|
||||
#define RFC1001_PORT 139
|
||||
|
||||
static DECLARE_COMPLETION(cifsd_complete);
|
||||
|
||||
extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
|
@ -60,6 +64,7 @@ struct smb_vol {
|
|||
char *in6_addr; /* ipv6 address as human readable form of in6_addr */
|
||||
char *iocharset; /* local code page for mapping to and from Unicode */
|
||||
char source_rfc1001_name[16]; /* netbios name of client */
|
||||
char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */
|
||||
uid_t linux_uid;
|
||||
gid_t linux_gid;
|
||||
mode_t file_mode;
|
||||
|
@ -74,6 +79,10 @@ struct smb_vol {
|
|||
unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
|
||||
unsigned direct_io:1;
|
||||
unsigned remap:1; /* set to remap seven reserved chars in filenames */
|
||||
unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
|
||||
unsigned sfu_emul:1;
|
||||
unsigned nocase; /* request case insensitive filenames */
|
||||
unsigned nobrl; /* disable sending byte range locks to srv */
|
||||
unsigned int rsize;
|
||||
unsigned int wsize;
|
||||
unsigned int sockopt;
|
||||
|
@ -82,7 +91,8 @@ struct smb_vol {
|
|||
|
||||
static int ipv4_connect(struct sockaddr_in *psin_server,
|
||||
struct socket **csocket,
|
||||
char * netb_name);
|
||||
char * netb_name,
|
||||
char * server_netb_name);
|
||||
static int ipv6_connect(struct sockaddr_in6 *psin_server,
|
||||
struct socket **csocket);
|
||||
|
||||
|
@ -175,9 +185,11 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
|||
} else {
|
||||
rc = ipv4_connect(&server->addr.sockAddr,
|
||||
&server->ssocket,
|
||||
server->workstation_RFC1001_name);
|
||||
server->workstation_RFC1001_name,
|
||||
server->server_RFC1001_name);
|
||||
}
|
||||
if(rc) {
|
||||
cFYI(1,("reconnect error %d",rc));
|
||||
msleep(3000);
|
||||
} else {
|
||||
atomic_inc(&tcpSesReconnectCount);
|
||||
|
@ -293,12 +305,12 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
|
|||
byte_count += total_in_buf2;
|
||||
BCC_LE(pTargetSMB) = cpu_to_le16(byte_count);
|
||||
|
||||
byte_count = be32_to_cpu(pTargetSMB->smb_buf_length);
|
||||
byte_count = pTargetSMB->smb_buf_length;
|
||||
byte_count += total_in_buf2;
|
||||
|
||||
/* BB also add check that we are not beyond maximum buffer size */
|
||||
|
||||
pTargetSMB->smb_buf_length = cpu_to_be32(byte_count);
|
||||
pTargetSMB->smb_buf_length = byte_count;
|
||||
|
||||
if(remaining == total_in_buf2) {
|
||||
cFYI(1,("found the last secondary response"));
|
||||
|
@ -323,7 +335,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
struct cifsSesInfo *ses;
|
||||
struct task_struct *task_to_wake = NULL;
|
||||
struct mid_q_entry *mid_entry;
|
||||
char *temp;
|
||||
char temp;
|
||||
int isLargeBuf = FALSE;
|
||||
int isMultiRsp;
|
||||
int reconnect;
|
||||
|
@ -337,6 +349,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
atomic_inc(&tcpSesAllocCount);
|
||||
length = tcpSesAllocCount.counter;
|
||||
write_unlock(&GlobalSMBSeslock);
|
||||
complete(&cifsd_complete);
|
||||
if(length > 1) {
|
||||
mempool_resize(cifs_req_poolp,
|
||||
length + cifs_min_rcv,
|
||||
|
@ -424,22 +437,32 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* the right amount was read from socket - 4 bytes */
|
||||
/* The right amount was read from socket - 4 bytes */
|
||||
/* so we can now interpret the length field */
|
||||
|
||||
/* the first byte big endian of the length field,
|
||||
is actually not part of the length but the type
|
||||
with the most common, zero, as regular data */
|
||||
temp = *((char *) smb_buffer);
|
||||
|
||||
/* Note that FC 1001 length is big endian on the wire,
|
||||
but we convert it here so it is always manipulated
|
||||
as host byte order */
|
||||
pdu_length = ntohl(smb_buffer->smb_buf_length);
|
||||
cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4));
|
||||
smb_buffer->smb_buf_length = pdu_length;
|
||||
|
||||
temp = (char *) smb_buffer;
|
||||
if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
|
||||
cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
|
||||
|
||||
if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
|
||||
continue;
|
||||
} else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
|
||||
} else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
|
||||
cFYI(1,("Good RFC 1002 session rsp"));
|
||||
continue;
|
||||
} else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
|
||||
} else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
|
||||
/* we get this from Windows 98 instead of
|
||||
an error on SMB negprot response */
|
||||
cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
|
||||
temp[4]));
|
||||
pdu_length));
|
||||
if(server->tcpStatus == CifsNew) {
|
||||
/* if nack on negprot (rather than
|
||||
ret of smb negprot error) reconnecting
|
||||
|
@ -461,9 +484,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
wake_up(&server->response_q);
|
||||
continue;
|
||||
}
|
||||
} else if (temp[0] != (char) 0) {
|
||||
} else if (temp != (char) 0) {
|
||||
cERROR(1,("Unknown RFC 1002 frame"));
|
||||
cifs_dump_mem(" Received Data: ", temp, length);
|
||||
cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
|
||||
length);
|
||||
cifs_reconnect(server);
|
||||
csocket = server->ssocket;
|
||||
continue;
|
||||
|
@ -533,7 +557,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
|
||||
dump_smb(smb_buffer, length);
|
||||
if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
|
||||
cERROR(1, ("Bad SMB Received "));
|
||||
cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -581,6 +605,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
|
|||
multi_t2_fnd:
|
||||
task_to_wake = mid_entry->tsk;
|
||||
mid_entry->midState = MID_RESPONSE_RECEIVED;
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
mid_entry->when_received = jiffies;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -598,7 +625,8 @@ multi_t2_fnd:
|
|||
} else if ((is_valid_oplock_break(smb_buffer) == FALSE)
|
||||
&& (isMultiRsp == FALSE)) {
|
||||
cERROR(1, ("No task to wake, unknown frame rcvd!"));
|
||||
cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
|
||||
cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
|
||||
sizeof(struct smb_hdr));
|
||||
}
|
||||
} /* end while !EXITING */
|
||||
|
||||
|
@ -676,7 +704,7 @@ multi_t2_fnd:
|
|||
msleep(125);
|
||||
}
|
||||
|
||||
if (list_empty(&server->pending_mid_q)) {
|
||||
if (!list_empty(&server->pending_mid_q)) {
|
||||
/* mpx threads have not exited yet give them
|
||||
at least the smb send timeout time for long ops */
|
||||
/* due to delays on oplock break requests, we need
|
||||
|
@ -713,7 +741,7 @@ multi_t2_fnd:
|
|||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
msleep(250);
|
||||
complete_and_exit(&cifsd_complete, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -737,7 +765,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
|
|||
toupper(system_utsname.nodename[i]);
|
||||
}
|
||||
vol->source_rfc1001_name[15] = 0;
|
||||
|
||||
/* null target name indicates to use *SMBSERVR default called name
|
||||
if we end up sending RFC1001 session initialize */
|
||||
vol->target_rfc1001_name[0] = 0;
|
||||
vol->linux_uid = current->uid; /* current->euid instead? */
|
||||
vol->linux_gid = current->gid;
|
||||
vol->dir_mode = S_IRWXUGO;
|
||||
|
@ -747,6 +777,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
|
|||
/* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
|
||||
vol->rw = TRUE;
|
||||
|
||||
/* default is always to request posix paths. */
|
||||
vol->posix_paths = 1;
|
||||
|
||||
if (!options)
|
||||
return 1;
|
||||
|
||||
|
@ -987,7 +1020,31 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
|
|||
/* The string has 16th byte zero still from
|
||||
set at top of the function */
|
||||
if((i==15) && (value[i] != 0))
|
||||
printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
|
||||
printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
|
||||
}
|
||||
} else if (strnicmp(data, "servern", 7) == 0) {
|
||||
/* servernetbiosname specified override *SMBSERVER */
|
||||
if (!value || !*value || (*value == ' ')) {
|
||||
cFYI(1,("empty server netbiosname specified"));
|
||||
} else {
|
||||
/* last byte, type, is 0x20 for servr type */
|
||||
memset(vol->target_rfc1001_name,0x20,16);
|
||||
|
||||
for(i=0;i<15;i++) {
|
||||
/* BB are there cases in which a comma can be
|
||||
valid in this workstation netbios name (and need
|
||||
special handling)? */
|
||||
|
||||
/* user or mount helper must uppercase netbiosname */
|
||||
if (value[i]==0)
|
||||
break;
|
||||
else
|
||||
vol->target_rfc1001_name[i] = value[i];
|
||||
}
|
||||
/* The string has 16th byte zero still from
|
||||
set at top of the function */
|
||||
if((i==15) && (value[i] != 0))
|
||||
printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
|
||||
}
|
||||
} else if (strnicmp(data, "credentials", 4) == 0) {
|
||||
/* ignore */
|
||||
|
@ -1025,6 +1082,27 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
|
|||
vol->remap = 1;
|
||||
} else if (strnicmp(data, "nomapchars", 10) == 0) {
|
||||
vol->remap = 0;
|
||||
} else if (strnicmp(data, "sfu", 3) == 0) {
|
||||
vol->sfu_emul = 1;
|
||||
} else if (strnicmp(data, "nosfu", 5) == 0) {
|
||||
vol->sfu_emul = 0;
|
||||
} else if (strnicmp(data, "posixpaths", 10) == 0) {
|
||||
vol->posix_paths = 1;
|
||||
} else if (strnicmp(data, "noposixpaths", 12) == 0) {
|
||||
vol->posix_paths = 0;
|
||||
} else if ((strnicmp(data, "nocase", 6) == 0) ||
|
||||
(strnicmp(data, "ignorecase", 10) == 0)) {
|
||||
vol->nocase = 1;
|
||||
} else if (strnicmp(data, "brl", 3) == 0) {
|
||||
vol->nobrl = 0;
|
||||
} else if ((strnicmp(data, "nobrl", 5) == 0) ||
|
||||
(strnicmp(data, "nolock", 6) == 0)) {
|
||||
vol->nobrl = 1;
|
||||
/* turn off mandatory locking in mode
|
||||
if remote locking is turned off since the
|
||||
local vfs will do advisory */
|
||||
if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
|
||||
vol->file_mode = S_IALLUGO;
|
||||
} else if (strnicmp(data, "setuids", 7) == 0) {
|
||||
vol->setuids = 1;
|
||||
} else if (strnicmp(data, "nosetuids", 9) == 0) {
|
||||
|
@ -1244,7 +1322,7 @@ static void rfc1002mangle(char * target,char * source, unsigned int length)
|
|||
|
||||
static int
|
||||
ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
|
||||
char * netbios_name)
|
||||
char * netbios_name, char * target_name)
|
||||
{
|
||||
int rc = 0;
|
||||
int connected = 0;
|
||||
|
@ -1309,10 +1387,16 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
|
|||
/* Eventually check for other socket options to change from
|
||||
the default. sock_setsockopt not used because it expects
|
||||
user space buffer */
|
||||
cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
|
||||
(*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
|
||||
(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
|
||||
/* make the bufsizes depend on wsize/rsize and max requests */
|
||||
if((*csocket)->sk->sk_sndbuf < (200 * 1024))
|
||||
(*csocket)->sk->sk_sndbuf = 200 * 1024;
|
||||
if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
|
||||
(*csocket)->sk->sk_rcvbuf = 140 * 1024;
|
||||
|
||||
/* send RFC1001 sessinit */
|
||||
|
||||
if(psin_server->sin_port == htons(RFC1001_PORT)) {
|
||||
/* some servers require RFC1001 sessinit before sending
|
||||
negprot - BB check reconnection in case where second
|
||||
|
@ -1322,8 +1406,14 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
|
|||
ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
|
||||
if(ses_init_buf) {
|
||||
ses_init_buf->trailer.session_req.called_len = 32;
|
||||
rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
|
||||
DEFAULT_CIFS_CALLED_NAME,16);
|
||||
if(target_name && (target_name[0] != 0)) {
|
||||
rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
|
||||
target_name, 16);
|
||||
} else {
|
||||
rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
|
||||
DEFAULT_CIFS_CALLED_NAME,16);
|
||||
}
|
||||
|
||||
ses_init_buf->trailer.session_req.calling_len = 32;
|
||||
/* calling name ends in null (byte 16) from old smb
|
||||
convention. */
|
||||
|
@ -1556,7 +1646,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
sin_server.sin_port = htons(volume_info.port);
|
||||
else
|
||||
sin_server.sin_port = 0;
|
||||
rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
|
||||
rc = ipv4_connect(&sin_server,&csocket,
|
||||
volume_info.source_rfc1001_name,
|
||||
volume_info.target_rfc1001_name);
|
||||
if (rc < 0) {
|
||||
cERROR(1,
|
||||
("Error connecting to IPv4 socket. Aborting operation"));
|
||||
|
@ -1606,9 +1698,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
kfree(volume_info.password);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
} else
|
||||
rc = 0;
|
||||
}
|
||||
wait_for_completion(&cifsd_complete);
|
||||
rc = 0;
|
||||
memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
|
||||
memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
|
||||
srvTcp->sequence_number = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1653,17 +1747,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
|
||||
/* search for existing tcon to this server share */
|
||||
if (!rc) {
|
||||
if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
|
||||
if(volume_info.rsize > CIFSMaxBufSize) {
|
||||
cERROR(1,("rsize %d too large, using MaxBufSize",
|
||||
volume_info.rsize));
|
||||
cifs_sb->rsize = CIFSMaxBufSize;
|
||||
} else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
|
||||
cifs_sb->rsize = volume_info.rsize;
|
||||
else
|
||||
cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
|
||||
if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize))
|
||||
else /* default */
|
||||
cifs_sb->rsize = CIFSMaxBufSize;
|
||||
|
||||
if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
|
||||
cERROR(1,("wsize %d too large using 4096 instead",
|
||||
volume_info.wsize));
|
||||
cifs_sb->wsize = 4096;
|
||||
} else if(volume_info.wsize)
|
||||
cifs_sb->wsize = volume_info.wsize;
|
||||
else
|
||||
cifs_sb->wsize = CIFSMaxBufSize; /* default */
|
||||
if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
|
||||
cifs_sb->rsize = PAGE_CACHE_SIZE;
|
||||
cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
|
||||
cifs_sb->rsize = PAGE_CACHE_SIZE;
|
||||
/* Windows ME does this */
|
||||
cFYI(1,("Attempt to set readsize for mount to less than one page (4096)"));
|
||||
}
|
||||
cifs_sb->mnt_uid = volume_info.linux_uid;
|
||||
cifs_sb->mnt_gid = volume_info.linux_gid;
|
||||
|
@ -1681,8 +1785,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
|
||||
if(volume_info.no_xattr)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
|
||||
if(volume_info.sfu_emul)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
|
||||
if(volume_info.nobrl)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
|
||||
|
||||
if(volume_info.direct_io) {
|
||||
cERROR(1,("mounting share using direct i/o"));
|
||||
cFYI(1,("mounting share using direct i/o"));
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
|
||||
}
|
||||
|
||||
|
@ -1696,6 +1805,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
to the same server share the last value passed in
|
||||
for the retry flag is used */
|
||||
tcon->retry = volume_info.retry;
|
||||
tcon->nocase = volume_info.nocase;
|
||||
} else {
|
||||
tcon = tconInfoAlloc();
|
||||
if (tcon == NULL)
|
||||
|
@ -1724,6 +1834,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
if (!rc) {
|
||||
atomic_inc(&pSesInfo->inUse);
|
||||
tcon->retry = volume_info.retry;
|
||||
tcon->nocase = volume_info.nocase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1745,8 +1856,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
spin_lock(&GlobalMid_Lock);
|
||||
srvTcp->tcpStatus = CifsExiting;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
if(srvTcp->tsk)
|
||||
if(srvTcp->tsk) {
|
||||
send_sig(SIGKILL,srvTcp->tsk,1);
|
||||
wait_for_completion(&cifsd_complete);
|
||||
}
|
||||
}
|
||||
/* If find_unc succeeded then rc == 0 so we can not end */
|
||||
if (tcon) /* up accidently freeing someone elses tcon struct */
|
||||
|
@ -1759,8 +1872,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
temp_rc = CIFSSMBLogoff(xid, pSesInfo);
|
||||
/* if the socketUseCount is now zero */
|
||||
if((temp_rc == -ESHUTDOWN) &&
|
||||
(pSesInfo->server->tsk))
|
||||
(pSesInfo->server->tsk)) {
|
||||
send_sig(SIGKILL,pSesInfo->server->tsk,1);
|
||||
wait_for_completion(&cifsd_complete);
|
||||
}
|
||||
} else
|
||||
cFYI(1, ("No session or bad tcon"));
|
||||
sesInfoFree(pSesInfo);
|
||||
|
@ -1783,8 +1898,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
cFYI(1,("server negotiated posix acl support"));
|
||||
sb->s_flags |= MS_POSIXACL;
|
||||
}
|
||||
|
||||
/* Try and negotiate POSIX pathnames if we can. */
|
||||
if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
|
||||
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
||||
if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
|
||||
cFYI(1,("negotiated posix pathnames support"));
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
|
||||
} else {
|
||||
cFYI(1,("posix pathnames support requested but not supported"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
|
||||
cifs_sb->wsize = min(cifs_sb->wsize,
|
||||
(tcon->ses->server->maxBuf -
|
||||
MAX_CIFS_HDR_SIZE));
|
||||
if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
|
||||
cifs_sb->rsize = min(cifs_sb->rsize,
|
||||
(tcon->ses->server->maxBuf -
|
||||
MAX_CIFS_HDR_SIZE));
|
||||
}
|
||||
|
||||
/* volume_info.password is freed above when existing session found
|
||||
|
@ -1832,6 +1966,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
|
||||
NULL /* no tCon exists yet */ , 13 /* wct */ );
|
||||
|
||||
smb_buffer->Mid = GetNextMid(ses->server);
|
||||
pSMB->req_no_secext.AndXCommand = 0xFF;
|
||||
pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
|
||||
pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
|
||||
|
@ -2107,6 +2242,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
/* send SMBsessionSetup here */
|
||||
header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
|
||||
NULL /* no tCon exists yet */ , 12 /* wct */ );
|
||||
|
||||
smb_buffer->Mid = GetNextMid(ses->server);
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
pSMB->req.AndXCommand = 0xFF;
|
||||
pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
|
||||
|
@ -2373,6 +2510,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
|||
/* send SMBsessionSetup here */
|
||||
header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
|
||||
NULL /* no tCon exists yet */ , 12 /* wct */ );
|
||||
|
||||
smb_buffer->Mid = GetNextMid(ses->server);
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
|
||||
|
||||
|
@ -2715,6 +2854,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
|||
/* send SMBsessionSetup here */
|
||||
header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
|
||||
NULL /* no tCon exists yet */ , 12 /* wct */ );
|
||||
|
||||
smb_buffer->Mid = GetNextMid(ses->server);
|
||||
pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
|
||||
pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||
pSMB->req.AndXCommand = 0xFF;
|
||||
|
@ -3086,6 +3227,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
|
|||
|
||||
header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
|
||||
NULL /*no tid */ , 4 /*wct */ );
|
||||
|
||||
smb_buffer->Mid = GetNextMid(ses->server);
|
||||
smb_buffer->Uid = ses->Suid;
|
||||
pSMB = (TCONX_REQ *) smb_buffer;
|
||||
pSMBr = (TCONX_RSP *) smb_buffer_response;
|
||||
|
@ -3207,8 +3350,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
|
|||
return 0;
|
||||
} else if (rc == -ESHUTDOWN) {
|
||||
cFYI(1,("Waking up socket by sending it signal"));
|
||||
if(cifsd_task)
|
||||
if(cifsd_task) {
|
||||
send_sig(SIGKILL,cifsd_task,1);
|
||||
wait_for_completion(&cifsd_complete);
|
||||
}
|
||||
rc = 0;
|
||||
} /* else - we have an smb session
|
||||
left on this socket do not kill cifsd */
|
||||
|
|
108
fs/cifs/dir.c
108
fs/cifs/dir.c
|
@ -48,6 +48,7 @@ build_path_from_dentry(struct dentry *direntry)
|
|||
struct dentry *temp;
|
||||
int namelen = 0;
|
||||
char *full_path;
|
||||
char dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
|
||||
|
||||
if(direntry == NULL)
|
||||
return NULL; /* not much we can do if dentry is freed and
|
||||
|
@ -74,7 +75,7 @@ cifs_bp_rename_retry:
|
|||
if (namelen < 0) {
|
||||
break;
|
||||
} else {
|
||||
full_path[namelen] = '\\';
|
||||
full_path[namelen] = dirsep;
|
||||
strncpy(full_path + namelen + 1, temp->d_name.name,
|
||||
temp->d_name.len);
|
||||
cFYI(0, (" name: %s ", full_path + namelen));
|
||||
|
@ -183,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
desiredAccess, CREATE_NOT_DIR,
|
||||
&fileHandle, &oplock, buf, cifs_sb->local_nls,
|
||||
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) {
|
||||
cFYI(1, ("cifs_create returned 0x%x ", rc));
|
||||
} else {
|
||||
|
@ -208,7 +216,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
}
|
||||
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);*/
|
||||
/* could set r/o dos attribute if mode & 0222 == 0 */
|
||||
}
|
||||
|
@ -225,10 +233,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
|
|||
}
|
||||
|
||||
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));
|
||||
} 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);
|
||||
}
|
||||
if((nd->flags & LOOKUP_OPEN) == FALSE) {
|
||||
|
@ -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);
|
||||
if(full_path == NULL)
|
||||
rc = -ENOMEM;
|
||||
|
||||
if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) {
|
||||
else if (pTcon->ses->capabilities & CAP_UNIX) {
|
||||
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
|
||||
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
|
||||
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
|
|||
if(!rc) {
|
||||
rc = cifs_get_inode_info_unix(&newinode, full_path,
|
||||
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)
|
||||
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);
|
||||
|
@ -381,7 +431,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
|
|||
parent_dir_inode->i_sb,xid);
|
||||
|
||||
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);
|
||||
|
||||
/* 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 = {
|
|||
/* 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 */
|
||||
};
|
||||
|
||||
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)
|
|||
__u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES;
|
||||
__u16 netfid;
|
||||
|
||||
|
||||
if(experimEnabled == 0)
|
||||
return 0;
|
||||
|
||||
xid = GetXid();
|
||||
cifs_sb = CIFS_SB(file->f_dentry->d_sb);
|
||||
pTcon = cifs_sb->tcon;
|
||||
|
@ -100,8 +104,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
|
|||
} else {
|
||||
filter = convert_to_cifs_notify_flags(arg);
|
||||
if(filter != 0) {
|
||||
rc = CIFSSMBNotify(xid, pTcon, 0 /* no subdirs */, netfid,
|
||||
filter, cifs_sb->local_nls);
|
||||
rc = CIFSSMBNotify(xid, pTcon,
|
||||
0 /* no subdirs */, netfid,
|
||||
filter, file, arg & DN_MULTISHOT,
|
||||
cifs_sb->local_nls);
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
@ -109,7 +115,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
|
|||
it would close automatically but may be a way
|
||||
to do it easily when inode freed or when
|
||||
notify info is cleared/changed */
|
||||
cERROR(1,("notify rc %d",rc));
|
||||
cFYI(1,("notify rc %d",rc));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
464
fs/cifs/file.c
464
fs/cifs/file.c
|
@ -21,11 +21,15 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <linux/fs.h>
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/mpage.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/pagevec.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/div64.h>
|
||||
#include "cifsfs.h"
|
||||
#include "cifspdu.h"
|
||||
|
@ -47,6 +51,11 @@ static inline struct cifsFileInfo *cifs_init_private(
|
|||
private_data->pInode = inode;
|
||||
private_data->invalidHandle = FALSE;
|
||||
private_data->closePend = FALSE;
|
||||
/* we have to track num writers to the inode, since writepages
|
||||
does not tell us which handle the write is for so there can
|
||||
be a close (overlapping with write) of the filehandle that
|
||||
cifs_writepages chose to use */
|
||||
atomic_set(&private_data->wrtPending,0);
|
||||
|
||||
return private_data;
|
||||
}
|
||||
|
@ -256,6 +265,13 @@ int cifs_open(struct inode *inode, struct file *file)
|
|||
CREATE_NOT_DIR, &netfid, &oplock, buf,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
|
||||
& CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc == -EIO) {
|
||||
/* Old server, try legacy style OpenX */
|
||||
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
|
||||
desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
|
||||
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
|
||||
& CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
}
|
||||
if (rc) {
|
||||
cFYI(1, ("cifs_open returned 0x%x ", rc));
|
||||
goto out;
|
||||
|
@ -463,6 +479,20 @@ int cifs_close(struct inode *inode, struct file *file)
|
|||
/* no sense reconnecting to close a file that is
|
||||
already closed */
|
||||
if (pTcon->tidStatus != CifsNeedReconnect) {
|
||||
int timeout = 2;
|
||||
while((atomic_read(&pSMBFile->wrtPending) != 0)
|
||||
&& (timeout < 1000) ) {
|
||||
/* Give write a better chance to get to
|
||||
server ahead of the close. We do not
|
||||
want to add a wait_q here as it would
|
||||
increase the memory utilization as
|
||||
the struct would be in each open file,
|
||||
but this should give enough time to
|
||||
clear the socket */
|
||||
cERROR(1,("close with pending writes"));
|
||||
msleep(timeout);
|
||||
timeout *= 4;
|
||||
}
|
||||
write_unlock(&file->f_owner.lock);
|
||||
rc = CIFSSMBClose(xid, pTcon,
|
||||
pSMBFile->netfid);
|
||||
|
@ -744,14 +774,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
|
|||
15 seconds is plenty */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
if (total_written > 0) {
|
||||
atomic_inc(&pTcon->num_writes);
|
||||
spin_lock(&pTcon->stat_lock);
|
||||
pTcon->bytes_written += total_written;
|
||||
spin_unlock(&pTcon->stat_lock);
|
||||
}
|
||||
#endif
|
||||
cifs_stats_bytes_written(pTcon, total_written);
|
||||
|
||||
/* since the write may have blocked check these pointers again */
|
||||
if (file->f_dentry) {
|
||||
|
@ -791,9 +814,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
|
|||
|
||||
pTcon = cifs_sb->tcon;
|
||||
|
||||
/* cFYI(1,
|
||||
(" write %d bytes to offset %lld of %s", write_size,
|
||||
*poffset, file->f_dentry->d_name.name)); */
|
||||
cFYI(1,("write %zd bytes to offset %lld of %s", write_size,
|
||||
*poffset, file->f_dentry->d_name.name));
|
||||
|
||||
if (file->private_data == NULL)
|
||||
return -EBADF;
|
||||
|
@ -846,7 +868,26 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
|
|||
if (rc != 0)
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
/* BB FIXME We can not sign across two buffers yet */
|
||||
if((experimEnabled) && ((pTcon->ses->server->secMode &
|
||||
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) {
|
||||
struct kvec iov[2];
|
||||
unsigned int len;
|
||||
|
||||
len = min((size_t)cifs_sb->wsize,
|
||||
write_size - total_written);
|
||||
/* iov[0] is reserved for smb header */
|
||||
iov[1].iov_base = (char *)write_data +
|
||||
total_written;
|
||||
iov[1].iov_len = len;
|
||||
rc = CIFSSMBWrite2(xid, pTcon,
|
||||
open_file->netfid, len,
|
||||
*poffset, &bytes_written,
|
||||
iov, 1, long_op);
|
||||
} else
|
||||
/* BB FIXME fixup indentation of line below */
|
||||
#endif
|
||||
rc = CIFSSMBWrite(xid, pTcon,
|
||||
open_file->netfid,
|
||||
min_t(const int, cifs_sb->wsize,
|
||||
|
@ -867,14 +908,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
|
|||
15 seconds is plenty */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
if (total_written > 0) {
|
||||
atomic_inc(&pTcon->num_writes);
|
||||
spin_lock(&pTcon->stat_lock);
|
||||
pTcon->bytes_written += total_written;
|
||||
spin_unlock(&pTcon->stat_lock);
|
||||
}
|
||||
#endif
|
||||
cifs_stats_bytes_written(pTcon, total_written);
|
||||
|
||||
/* since the write may have blocked check these pointers again */
|
||||
if (file->f_dentry) {
|
||||
|
@ -893,6 +927,43 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
|
|||
return total_written;
|
||||
}
|
||||
|
||||
struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
|
||||
{
|
||||
struct cifsFileInfo *open_file;
|
||||
int rc;
|
||||
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
|
||||
if (open_file->closePend)
|
||||
continue;
|
||||
if (open_file->pfile &&
|
||||
((open_file->pfile->f_flags & O_RDWR) ||
|
||||
(open_file->pfile->f_flags & O_WRONLY))) {
|
||||
atomic_inc(&open_file->wrtPending);
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
if((open_file->invalidHandle) &&
|
||||
(!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
|
||||
rc = cifs_reopen_file(&cifs_inode->vfs_inode,
|
||||
open_file->pfile, FALSE);
|
||||
/* if it fails, try another handle - might be */
|
||||
/* dangerous to hold up writepages with retry */
|
||||
if(rc) {
|
||||
cFYI(1,("failed on reopen file in wp"));
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
/* can not use this handle, no write
|
||||
pending on this one after all */
|
||||
atomic_dec
|
||||
(&open_file->wrtPending);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return open_file;
|
||||
}
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
||||
{
|
||||
struct address_space *mapping = page->mapping;
|
||||
|
@ -903,10 +974,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
|||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *pTcon;
|
||||
struct inode *inode;
|
||||
struct cifsInodeInfo *cifsInode;
|
||||
struct cifsFileInfo *open_file = NULL;
|
||||
struct list_head *tmp;
|
||||
struct list_head *tmp1;
|
||||
struct cifsFileInfo *open_file;
|
||||
|
||||
if (!mapping || !mapping->host)
|
||||
return -EFAULT;
|
||||
|
@ -934,49 +1002,20 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
|||
if (mapping->host->i_size - offset < (loff_t)to)
|
||||
to = (unsigned)(mapping->host->i_size - offset);
|
||||
|
||||
cifsInode = CIFS_I(mapping->host);
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
/* BB we should start at the end */
|
||||
list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {
|
||||
open_file = list_entry(tmp, struct cifsFileInfo, flist);
|
||||
if (open_file->closePend)
|
||||
continue;
|
||||
/* We check if file is open for writing first */
|
||||
if ((open_file->pfile) &&
|
||||
((open_file->pfile->f_flags & O_RDWR) ||
|
||||
(open_file->pfile->f_flags & O_WRONLY))) {
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
bytes_written = cifs_write(open_file->pfile,
|
||||
write_data, to-from,
|
||||
&offset);
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
open_file = find_writable_file(CIFS_I(mapping->host));
|
||||
if (open_file) {
|
||||
bytes_written = cifs_write(open_file->pfile, write_data,
|
||||
to-from, &offset);
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
/* Does mm or vfs already set times? */
|
||||
inode->i_atime =
|
||||
inode->i_mtime = current_fs_time(inode->i_sb);
|
||||
if ((bytes_written > 0) && (offset)) {
|
||||
rc = 0;
|
||||
} else if (bytes_written < 0) {
|
||||
if (rc == -EBADF) {
|
||||
/* have seen a case in which kernel seemed to
|
||||
have closed/freed a file even with writes
|
||||
active so we might as well see if there are
|
||||
other file structs to try for the same
|
||||
inode before giving up */
|
||||
continue;
|
||||
} else
|
||||
rc = bytes_written;
|
||||
}
|
||||
break; /* now that we found a valid file handle and
|
||||
tried to write to it we are done, no sense
|
||||
continuing to loop looking for another */
|
||||
inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);
|
||||
if ((bytes_written > 0) && (offset)) {
|
||||
rc = 0;
|
||||
} else if (bytes_written < 0) {
|
||||
if (rc != -EBADF)
|
||||
rc = bytes_written;
|
||||
}
|
||||
if (tmp->next == NULL) {
|
||||
cFYI(1, ("File instance %p removed", tmp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
if (open_file == NULL) {
|
||||
} else {
|
||||
cFYI(1, ("No writeable filehandles for inode"));
|
||||
rc = -EIO;
|
||||
}
|
||||
|
@ -985,20 +1024,207 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
|
|||
return rc;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
static int cifs_writepages(struct address_space *mapping,
|
||||
struct writeback_control *wbc)
|
||||
struct writeback_control *wbc)
|
||||
{
|
||||
int rc = -EFAULT;
|
||||
struct backing_dev_info *bdi = mapping->backing_dev_info;
|
||||
unsigned int bytes_to_write;
|
||||
unsigned int bytes_written;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
int done = 0;
|
||||
pgoff_t end = -1;
|
||||
pgoff_t index;
|
||||
int is_range = 0;
|
||||
struct kvec iov[32];
|
||||
int len;
|
||||
int n_iov = 0;
|
||||
pgoff_t next;
|
||||
int nr_pages;
|
||||
__u64 offset = 0;
|
||||
struct cifsFileInfo *open_file;
|
||||
struct page *page;
|
||||
struct pagevec pvec;
|
||||
int rc = 0;
|
||||
int scanned = 0;
|
||||
int xid;
|
||||
|
||||
cifs_sb = CIFS_SB(mapping->host->i_sb);
|
||||
|
||||
/*
|
||||
* If wsize is smaller that the page cache size, default to writing
|
||||
* one page at a time via cifs_writepage
|
||||
*/
|
||||
if (cifs_sb->wsize < PAGE_CACHE_SIZE)
|
||||
return generic_writepages(mapping, wbc);
|
||||
|
||||
/* BB FIXME we do not have code to sign across multiple buffers yet,
|
||||
so go to older writepage style write which we can sign if needed */
|
||||
if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
|
||||
if(cifs_sb->tcon->ses->server->secMode &
|
||||
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
|
||||
return generic_writepages(mapping, wbc);
|
||||
|
||||
/*
|
||||
* BB: Is this meaningful for a non-block-device file system?
|
||||
* If it is, we should test it again after we do I/O
|
||||
*/
|
||||
if (wbc->nonblocking && bdi_write_congested(bdi)) {
|
||||
wbc->encountered_congestion = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
/* Find contiguous pages then iterate through repeating
|
||||
call 16K write then Setpageuptodate or if LARGE_WRITE_X
|
||||
support then send larger writes via kevec so as to eliminate
|
||||
a memcpy */
|
||||
pagevec_init(&pvec, 0);
|
||||
if (wbc->sync_mode == WB_SYNC_NONE)
|
||||
index = mapping->writeback_index; /* Start from prev offset */
|
||||
else {
|
||||
index = 0;
|
||||
scanned = 1;
|
||||
}
|
||||
if (wbc->start || wbc->end) {
|
||||
index = wbc->start >> PAGE_CACHE_SHIFT;
|
||||
end = wbc->end >> PAGE_CACHE_SHIFT;
|
||||
is_range = 1;
|
||||
scanned = 1;
|
||||
}
|
||||
retry:
|
||||
while (!done && (index <= end) &&
|
||||
(nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
|
||||
PAGECACHE_TAG_DIRTY,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {
|
||||
int first;
|
||||
unsigned int i;
|
||||
|
||||
first = -1;
|
||||
next = 0;
|
||||
n_iov = 0;
|
||||
bytes_to_write = 0;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
page = pvec.pages[i];
|
||||
/*
|
||||
* At this point we hold neither mapping->tree_lock nor
|
||||
* lock on the page itself: the page may be truncated or
|
||||
* invalidated (changing page->mapping to NULL), or even
|
||||
* swizzled back from swapper_space to tmpfs file
|
||||
* mapping
|
||||
*/
|
||||
|
||||
if (first < 0)
|
||||
lock_page(page);
|
||||
else if (TestSetPageLocked(page))
|
||||
break;
|
||||
|
||||
if (unlikely(page->mapping != mapping)) {
|
||||
unlock_page(page);
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(is_range) && (page->index > end)) {
|
||||
done = 1;
|
||||
unlock_page(page);
|
||||
break;
|
||||
}
|
||||
|
||||
if (next && (page->index != next)) {
|
||||
/* Not next consecutive page */
|
||||
unlock_page(page);
|
||||
break;
|
||||
}
|
||||
|
||||
if (wbc->sync_mode != WB_SYNC_NONE)
|
||||
wait_on_page_writeback(page);
|
||||
|
||||
if (PageWriteback(page) ||
|
||||
!test_clear_page_dirty(page)) {
|
||||
unlock_page(page);
|
||||
break;
|
||||
}
|
||||
|
||||
if (page_offset(page) >= mapping->host->i_size) {
|
||||
done = 1;
|
||||
unlock_page(page);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* BB can we get rid of this? pages are held by pvec
|
||||
*/
|
||||
page_cache_get(page);
|
||||
|
||||
len = min(mapping->host->i_size - page_offset(page),
|
||||
(loff_t)PAGE_CACHE_SIZE);
|
||||
|
||||
/* reserve iov[0] for the smb header */
|
||||
n_iov++;
|
||||
iov[n_iov].iov_base = kmap(page);
|
||||
iov[n_iov].iov_len = len;
|
||||
bytes_to_write += len;
|
||||
|
||||
if (first < 0) {
|
||||
first = i;
|
||||
offset = page_offset(page);
|
||||
}
|
||||
next = page->index + 1;
|
||||
if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)
|
||||
break;
|
||||
}
|
||||
if (n_iov) {
|
||||
/* Search for a writable handle every time we call
|
||||
* CIFSSMBWrite2. We can't rely on the last handle
|
||||
* we used to still be valid
|
||||
*/
|
||||
open_file = find_writable_file(CIFS_I(mapping->host));
|
||||
if (!open_file) {
|
||||
cERROR(1, ("No writable handles for inode"));
|
||||
rc = -EBADF;
|
||||
} else {
|
||||
rc = CIFSSMBWrite2(xid, cifs_sb->tcon,
|
||||
open_file->netfid,
|
||||
bytes_to_write, offset,
|
||||
&bytes_written, iov, n_iov,
|
||||
1);
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
if (rc || bytes_written < bytes_to_write) {
|
||||
cERROR(1,("Write2 ret %d, written = %d",
|
||||
rc, bytes_written));
|
||||
/* BB what if continued retry is
|
||||
requested via mount flags? */
|
||||
set_bit(AS_EIO, &mapping->flags);
|
||||
SetPageError(page);
|
||||
} else {
|
||||
cifs_stats_bytes_written(cifs_sb->tcon,
|
||||
bytes_written);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < n_iov; i++) {
|
||||
page = pvec.pages[first + i];
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
if ((wbc->nr_to_write -= n_iov) <= 0)
|
||||
done = 1;
|
||||
index = next;
|
||||
}
|
||||
pagevec_release(&pvec);
|
||||
}
|
||||
if (!scanned && !done) {
|
||||
/*
|
||||
* We hit the last page and there is more work to be done: wrap
|
||||
* back to the start of the file
|
||||
*/
|
||||
scanned = 1;
|
||||
index = 0;
|
||||
goto retry;
|
||||
}
|
||||
if (!is_range)
|
||||
mapping->writeback_index = index;
|
||||
|
||||
FreeXid(xid);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
@ -1207,12 +1433,10 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
|
|||
if (rc != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
rc = CIFSSMBRead(xid, pTcon,
|
||||
open_file->netfid,
|
||||
current_read_size, *poffset,
|
||||
&bytes_read, &smb_read_data);
|
||||
|
||||
open_file->netfid,
|
||||
current_read_size, *poffset,
|
||||
&bytes_read, &smb_read_data);
|
||||
pSMBr = (struct smb_com_read_rsp *)smb_read_data;
|
||||
if (copy_to_user(current_offset,
|
||||
smb_read_data + 4 /* RFC1001 hdr */
|
||||
|
@ -1235,12 +1459,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
|
|||
return rc;
|
||||
}
|
||||
} else {
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
atomic_inc(&pTcon->num_reads);
|
||||
spin_lock(&pTcon->stat_lock);
|
||||
pTcon->bytes_read += total_read;
|
||||
spin_unlock(&pTcon->stat_lock);
|
||||
#endif
|
||||
cifs_stats_bytes_read(pTcon, bytes_read);
|
||||
*poffset += bytes_read;
|
||||
}
|
||||
}
|
||||
|
@ -1280,6 +1499,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
|
|||
total_read += bytes_read, current_offset += bytes_read) {
|
||||
current_read_size = min_t(const int, read_size - total_read,
|
||||
cifs_sb->rsize);
|
||||
/* For windows me and 9x we do not want to request more
|
||||
than it negotiated since it will refuse the read then */
|
||||
if((pTcon->ses) &&
|
||||
!(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
|
||||
current_read_size = min_t(const int, current_read_size,
|
||||
pTcon->ses->server->maxBuf - 128);
|
||||
}
|
||||
rc = -EAGAIN;
|
||||
while (rc == -EAGAIN) {
|
||||
if ((open_file->invalidHandle) &&
|
||||
|
@ -1289,11 +1515,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
|
|||
if (rc != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
rc = CIFSSMBRead(xid, pTcon,
|
||||
open_file->netfid,
|
||||
current_read_size, *poffset,
|
||||
&bytes_read, ¤t_offset);
|
||||
open_file->netfid,
|
||||
current_read_size, *poffset,
|
||||
&bytes_read, ¤t_offset);
|
||||
}
|
||||
if (rc || (bytes_read == 0)) {
|
||||
if (total_read) {
|
||||
|
@ -1303,12 +1528,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
|
|||
return rc;
|
||||
}
|
||||
} else {
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
atomic_inc(&pTcon->num_reads);
|
||||
spin_lock(&pTcon->stat_lock);
|
||||
pTcon->bytes_read += total_read;
|
||||
spin_unlock(&pTcon->stat_lock);
|
||||
#endif
|
||||
cifs_stats_bytes_read(pTcon, total_read);
|
||||
*poffset += bytes_read;
|
||||
}
|
||||
}
|
||||
|
@ -1452,10 +1672,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
|
|||
}
|
||||
|
||||
rc = CIFSSMBRead(xid, pTcon,
|
||||
open_file->netfid,
|
||||
read_size, offset,
|
||||
&bytes_read, &smb_read_data);
|
||||
/* BB need to check return code here */
|
||||
open_file->netfid,
|
||||
read_size, offset,
|
||||
&bytes_read, &smb_read_data);
|
||||
|
||||
/* BB more RC checks ? */
|
||||
if (rc== -EAGAIN) {
|
||||
if (smb_read_data) {
|
||||
cifs_buf_release(smb_read_data);
|
||||
|
@ -1480,12 +1701,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
|
|||
le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
|
||||
|
||||
i += bytes_read >> PAGE_CACHE_SHIFT;
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
atomic_inc(&pTcon->num_reads);
|
||||
spin_lock(&pTcon->stat_lock);
|
||||
pTcon->bytes_read += bytes_read;
|
||||
spin_unlock(&pTcon->stat_lock);
|
||||
#endif
|
||||
cifs_stats_bytes_read(pTcon, bytes_read);
|
||||
if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
|
||||
i++; /* account for partial page */
|
||||
|
||||
|
@ -1603,40 +1819,21 @@ static int cifs_readpage(struct file *file, struct page *page)
|
|||
page caching in the current Linux kernel design */
|
||||
int is_size_safe_to_change(struct cifsInodeInfo *cifsInode)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct list_head *tmp1;
|
||||
struct cifsFileInfo *open_file = NULL;
|
||||
int rc = TRUE;
|
||||
|
||||
if (cifsInode == NULL)
|
||||
return rc;
|
||||
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {
|
||||
open_file = list_entry(tmp, struct cifsFileInfo, flist);
|
||||
if (open_file == NULL)
|
||||
break;
|
||||
if (open_file->closePend)
|
||||
continue;
|
||||
/* We check if file is open for writing,
|
||||
BB we could supplement this with a check to see if file size
|
||||
changes have been flushed to server - ie inode metadata dirty */
|
||||
if ((open_file->pfile) &&
|
||||
((open_file->pfile->f_flags & O_RDWR) ||
|
||||
(open_file->pfile->f_flags & O_WRONLY))) {
|
||||
rc = FALSE;
|
||||
break;
|
||||
}
|
||||
if (tmp->next == NULL) {
|
||||
cFYI(1, ("File instance %p removed", tmp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
return rc;
|
||||
if (cifsInode)
|
||||
open_file = find_writable_file(cifsInode);
|
||||
|
||||
if(open_file) {
|
||||
/* there is not actually a write pending so let
|
||||
this handle go free and allow it to
|
||||
be closable if needed */
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
return 0;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int cifs_prepare_write(struct file *file, struct page *page,
|
||||
unsigned from, unsigned to)
|
||||
{
|
||||
|
@ -1676,6 +1873,9 @@ struct address_space_operations cifs_addr_ops = {
|
|||
.readpage = cifs_readpage,
|
||||
.readpages = cifs_readpages,
|
||||
.writepage = cifs_writepage,
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
.writepages = cifs_writepages,
|
||||
#endif
|
||||
.prepare_write = cifs_prepare_write,
|
||||
.commit_write = cifs_commit_write,
|
||||
.set_page_dirty = __set_page_dirty_nobuffers,
|
||||
|
|
150
fs/cifs/inode.c
150
fs/cifs/inode.c
|
@ -166,7 +166,13 @@ int cifs_get_inode_info_unix(struct inode **pinode,
|
|||
inode->i_fop = &cifs_file_direct_ops;
|
||||
else
|
||||
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;
|
||||
/* 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)) {
|
||||
cFYI(1, (" Directory inode"));
|
||||
inode->i_op = &cifs_dir_inode_ops;
|
||||
|
@ -213,8 +219,18 @@ int cifs_get_inode_info(struct inode **pinode,
|
|||
pfindData = (FILE_ALL_INFO *)buf;
|
||||
/* could do find first instead but this returns more info */
|
||||
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);
|
||||
/* 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)); */
|
||||
if (rc) {
|
||||
|
@ -320,6 +336,16 @@ int cifs_get_inode_info(struct inode **pinode,
|
|||
on dirs */
|
||||
inode->i_mode = cifs_sb->mnt_dir_mode;
|
||||
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 {
|
||||
inode->i_mode |= S_IFREG;
|
||||
/* treat the dos attribute of read-only as read-only
|
||||
|
@ -359,7 +385,12 @@ int cifs_get_inode_info(struct inode **pinode,
|
|||
inode->i_fop = &cifs_file_direct_ops;
|
||||
else
|
||||
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;
|
||||
if(pTcon->ses->server->maxBuf <
|
||||
4096 + MAX_CIFS_HDR_SIZE)
|
||||
inode->i_data.a_ops->readpages = NULL;
|
||||
} else if (S_ISDIR(inode->i_mode)) {
|
||||
cFYI(1, (" Directory inode "));
|
||||
inode->i_op = &cifs_dir_inode_ops;
|
||||
|
@ -577,7 +608,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
|
|||
rc = cifs_get_inode_info(&newinode, full_path, NULL,
|
||||
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);
|
||||
if (direntry->d_inode)
|
||||
direntry->d_inode->i_nlink = 2;
|
||||
|
@ -928,7 +962,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||
struct cifsTconInfo *pTcon;
|
||||
char *full_path = NULL;
|
||||
int rc = -EACCES;
|
||||
int found = FALSE;
|
||||
struct cifsFileInfo *open_file = NULL;
|
||||
FILE_BASIC_INFO time_buf;
|
||||
int set_time = FALSE;
|
||||
|
@ -936,7 +969,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||
__u64 uid = 0xFFFFFFFFFFFFFFFFULL;
|
||||
__u64 gid = 0xFFFFFFFFFFFFFFFFULL;
|
||||
struct cifsInodeInfo *cifsInode;
|
||||
struct list_head *tmp;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
|
@ -961,7 +993,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||
filemap_fdatawait(direntry->d_inode->i_mapping);
|
||||
|
||||
if (attrs->ia_valid & ATTR_SIZE) {
|
||||
read_lock(&GlobalSMBSeslock);
|
||||
/* To avoid spurious oplock breaks from server, in the case of
|
||||
inodes that we already have open, avoid doing path based
|
||||
setting of file size if we can do it by handle.
|
||||
|
@ -969,40 +1000,23 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||
when the local oplock break takes longer to flush
|
||||
writebehind data than the SMB timeout for the SetPathInfo
|
||||
request would allow */
|
||||
list_for_each(tmp, &cifsInode->openFileList) {
|
||||
open_file = list_entry(tmp, struct cifsFileInfo,
|
||||
flist);
|
||||
/* We check if file is open for writing first */
|
||||
if ((open_file->pfile) &&
|
||||
((open_file->pfile->f_flags & O_RDWR) ||
|
||||
(open_file->pfile->f_flags & O_WRONLY))) {
|
||||
if (open_file->invalidHandle == FALSE) {
|
||||
/* we found a valid, writeable network
|
||||
file handle to use to try to set the
|
||||
file size */
|
||||
__u16 nfid = open_file->netfid;
|
||||
__u32 npid = open_file->pid;
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
found = TRUE;
|
||||
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;
|
||||
}
|
||||
open_file = find_writable_file(cifsInode);
|
||||
if (open_file) {
|
||||
__u16 nfid = open_file->netfid;
|
||||
__u32 npid = open_file->pid;
|
||||
rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
|
||||
nfid, npid, FALSE);
|
||||
atomic_dec(&open_file->wrtPending);
|
||||
cFYI(1,("SetFSize for attrs rc = %d", rc));
|
||||
if(rc == -EINVAL) {
|
||||
int bytes_written;
|
||||
rc = CIFSSMBWrite(xid, pTcon,
|
||||
nfid, 0, attrs->ia_size,
|
||||
&bytes_written, NULL, NULL,
|
||||
1 /* 45 seconds */);
|
||||
cFYI(1,("Wrt seteof rc %d", rc));
|
||||
}
|
||||
}
|
||||
if (found == FALSE)
|
||||
read_unlock(&GlobalSMBSeslock);
|
||||
|
||||
if (rc != 0) {
|
||||
/* Set file size by pathname rather than by handle
|
||||
either because no valid, writeable file handle for
|
||||
|
@ -1013,7 +1027,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
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
|
||||
|
@ -1026,24 +1063,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||
rc = vmtruncate(direntry->d_inode, attrs->ia_size);
|
||||
cifs_truncate_page(direntry->d_inode->i_mapping,
|
||||
direntry->d_inode->i_size);
|
||||
}
|
||||
} else
|
||||
goto cifs_setattr_exit;
|
||||
}
|
||||
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;
|
||||
/* entry->uid = cpu_to_le16(attr->ia_uid); */
|
||||
}
|
||||
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;
|
||||
/* entry->gid = cpu_to_le16(attr->ia_gid); */
|
||||
}
|
||||
|
||||
time_buf.Attributes = 0;
|
||||
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;
|
||||
/* entry->mode = cpu_to_le16(attr->ia_mode); */
|
||||
}
|
||||
|
||||
if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
|
||||
|
@ -1083,18 +1118,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
|
||||
} else
|
||||
time_buf.LastWriteTime = 0;
|
||||
|
||||
if (attrs->ia_valid & ATTR_CTIME) {
|
||||
/* Do not set ctime explicitly unless other time
|
||||
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;
|
||||
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 =
|
||||
cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
|
||||
} else
|
||||
time_buf.ChangeTime = 0;
|
||||
|
||||
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 */
|
||||
/* In the future we should experiment - try setting timestamps
|
||||
via Handle (SetFileInfo) instead of by path */
|
||||
|
@ -1133,12 +1174,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
|||
&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
|
||||
that */
|
||||
if (!rc)
|
||||
rc = inode_setattr(direntry->d_inode, attrs);
|
||||
cifs_setattr_exit:
|
||||
kfree(full_path);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
|
|
|
@ -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 ",
|
||||
rc));
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
|
123
fs/cifs/misc.c
123
fs/cifs/misc.c
|
@ -34,8 +34,6 @@ extern mempool_t *cifs_sm_req_poolp;
|
|||
extern mempool_t *cifs_req_poolp;
|
||||
extern struct task_struct * oplockThread;
|
||||
|
||||
static __u16 GlobalMid; /* multiplex id - rotating counter */
|
||||
|
||||
/* 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,
|
||||
and CurrentXid can also provide a running counter (although it
|
||||
|
@ -51,6 +49,8 @@ _GetXid(void)
|
|||
GlobalTotalActiveXid++;
|
||||
if (GlobalTotalActiveXid > GlobalMaxActiveXid)
|
||||
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++;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
return xid;
|
||||
|
@ -218,6 +218,76 @@ cifs_small_buf_release(void *buf_to_free)
|
|||
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
|
||||
header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
||||
const struct cifsTconInfo *treeCon, int word_count
|
||||
|
@ -233,7 +303,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
|||
(2 * word_count) + sizeof (struct smb_hdr) -
|
||||
4 /* RFC 1001 length field does not count */ +
|
||||
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[1] = 'S';
|
||||
|
@ -245,8 +316,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
|||
buffer->Pid = cpu_to_le16((__u16)current->tgid);
|
||||
buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
GlobalMid++;
|
||||
buffer->Mid = GlobalMid;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
if (treeCon) {
|
||||
buffer->Tid = treeCon->tid;
|
||||
|
@ -256,8 +325,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
|||
if (treeCon->ses->capabilities & CAP_STATUS32) {
|
||||
buffer->Flags2 |= SMBFLG2_ERR_STATUS;
|
||||
}
|
||||
|
||||
buffer->Uid = treeCon->ses->Suid; /* always in LE format */
|
||||
/* Uid is not converted */
|
||||
buffer->Uid = treeCon->ses->Suid;
|
||||
buffer->Mid = GetNextMid(treeCon->ses->server);
|
||||
if(multiuser_mount != 0) {
|
||||
/* For the multiuser case, there are few obvious technically */
|
||||
/* possible mechanisms to match the local linux user (uid) */
|
||||
|
@ -305,6 +375,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
|
|||
}
|
||||
if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
|
||||
buffer->Flags2 |= SMBFLG2_DFS;
|
||||
if (treeCon->nocase)
|
||||
buffer->Flags |= SMBFLG_CASELESS;
|
||||
if((treeCon->ses) && (treeCon->ses->server))
|
||||
if(treeCon->ses->server->secMode &
|
||||
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
|
||||
|
@ -347,7 +419,8 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
|
|||
int
|
||||
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,
|
||||
("Entering checkSMB with Length: %x, smb_buf_length: %x ",
|
||||
length, len));
|
||||
|
@ -368,23 +441,29 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
|
|||
cERROR(1,
|
||||
("smb_buf_length greater than MaxBufSize"));
|
||||
cERROR(1,
|
||||
("bad smb detected. Illegal length. The mid=%d",
|
||||
("bad smb detected. Illegal length. mid=%d",
|
||||
smb->Mid));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (checkSMBhdr(smb, mid))
|
||||
return 1;
|
||||
|
||||
if ((4 + len != smbCalcSize(smb))
|
||||
clc_len = smbCalcSize_LE(smb);
|
||||
if ((4 + len != clc_len)
|
||||
|| (4 + len != (unsigned int)length)) {
|
||||
return 0;
|
||||
} else {
|
||||
cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
|
||||
cERROR(1,
|
||||
("bad smb size detected. The Mid=%d", smb->Mid));
|
||||
return 1;
|
||||
cERROR(1, ("Calculated size 0x%x vs actual length 0x%x",
|
||||
clc_len, 4 + len));
|
||||
cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid));
|
||||
/* Windows XP can return a few bytes too much, presumably
|
||||
an illegal pad, at the end of byte range lock responses
|
||||
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
|
||||
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) {
|
||||
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
|
||||
if (tcon->tid == buf->Tid) {
|
||||
#ifdef CONFIG_CIFS_STATS
|
||||
atomic_inc(&tcon->num_oplock_brks);
|
||||
#endif
|
||||
cifs_stats_inc(&tcon->num_oplock_brks);
|
||||
list_for_each(tmp1,&tcon->openFileList){
|
||||
netfile = list_entry(tmp1,struct cifsFileInfo,
|
||||
tlist);
|
||||
|
@ -603,6 +680,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
|
|||
int i,j,charlen;
|
||||
int len_remaining = maxlen;
|
||||
char src_char;
|
||||
__u16 temp;
|
||||
|
||||
if(!mapChars)
|
||||
return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp);
|
||||
|
@ -639,13 +717,14 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
|
|||
break;*/
|
||||
default:
|
||||
charlen = cp->char2uni(source+i,
|
||||
len_remaining, target+j);
|
||||
len_remaining, &temp);
|
||||
/* if no match, use question mark, which
|
||||
at least in some cases servers as wild card */
|
||||
if(charlen < 1) {
|
||||
target[j] = cpu_to_le16(0x003f);
|
||||
charlen = 1;
|
||||
}
|
||||
} else
|
||||
target[j] = cpu_to_le16(temp);
|
||||
len_remaining -= charlen;
|
||||
/* character may take more than one byte in the
|
||||
the source string, but will take exactly two
|
||||
|
|
|
@ -133,7 +133,6 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
|
|||
int
|
||||
cifs_inet_pton(int address_family, char *cp,void *dst)
|
||||
{
|
||||
struct in_addr address;
|
||||
int value;
|
||||
int digit;
|
||||
int i;
|
||||
|
@ -190,8 +189,7 @@ cifs_inet_pton(int address_family, char *cp,void *dst)
|
|||
if (value > addr_class_max[end - bytes])
|
||||
return 0;
|
||||
|
||||
address.s_addr = *((__be32 *) bytes) | htonl(value);
|
||||
*((__be32 *)dst) = address.s_addr;
|
||||
*((__be32 *)dst) = *((__be32 *) bytes) | htonl(value);
|
||||
return 1; /* success */
|
||||
}
|
||||
|
||||
|
@ -815,7 +813,7 @@ map_smb_to_linux_error(struct smb_hdr *smb)
|
|||
if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
|
||||
/* translate the newer STATUS codes to old style errors and then to POSIX errors */
|
||||
__u32 err = le32_to_cpu(smb->Status.CifsError);
|
||||
if(cifsFYI)
|
||||
if(cifsFYI & CIFS_RC)
|
||||
cifs_print_status(err);
|
||||
ntstatus_to_dos(err, &smberrclass, &smberrcode);
|
||||
} else {
|
||||
|
@ -870,7 +868,14 @@ unsigned int
|
|||
smbCalcSize(struct smb_hdr *ptr)
|
||||
{
|
||||
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 */
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
#define NTLMSSP_SIGNATURE "NTLMSSP"
|
||||
/* Message Types */
|
||||
#define NtLmNegotiate cpu_to_le32(1)
|
||||
|
@ -63,7 +61,7 @@ typedef struct _SECURITY_BUFFER {
|
|||
__le16 Length;
|
||||
__le16 MaximumLength;
|
||||
__le32 Buffer; /* offset to buffer */
|
||||
} SECURITY_BUFFER;
|
||||
} __attribute__((packed)) SECURITY_BUFFER;
|
||||
|
||||
typedef struct _NEGOTIATE_MESSAGE {
|
||||
__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
|
||||
|
@ -73,7 +71,7 @@ typedef struct _NEGOTIATE_MESSAGE {
|
|||
SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */
|
||||
char DomainString[0];
|
||||
/* followed by WorkstationString */
|
||||
} NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
|
||||
} __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
|
||||
|
||||
typedef struct _CHALLENGE_MESSAGE {
|
||||
__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
|
||||
|
@ -83,7 +81,7 @@ typedef struct _CHALLENGE_MESSAGE {
|
|||
__u8 Challenge[CIFS_CRYPTO_KEY_SIZE];
|
||||
__u8 Reserved[8];
|
||||
SECURITY_BUFFER TargetInfoArray;
|
||||
} CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
|
||||
} __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
|
||||
|
||||
typedef struct _AUTHENTICATE_MESSAGE {
|
||||
__u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
|
||||
|
@ -96,6 +94,4 @@ typedef struct _AUTHENTICATE_MESSAGE {
|
|||
SECURITY_BUFFER SessionKey;
|
||||
__le32 NegotiateFlags;
|
||||
char UserString[0];
|
||||
} AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
|
||||
|
||||
#pragma pack() /* resume default structure packing */
|
||||
} __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
|
||||
|
|
|
@ -91,7 +91,10 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
|
|||
}
|
||||
|
||||
*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)
|
||||
return rc;
|
||||
rc = 1;
|
||||
|
@ -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 |= 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 */
|
||||
/* } else if (attr & ATTR_REPARSE) {
|
||||
*pobject_type = DT_LNK;
|
||||
|
@ -187,11 +197,17 @@ static void fill_in_inode(struct inode *tmp_inode,
|
|||
tmp_inode->i_fop = &cifs_file_direct_ops;
|
||||
else
|
||||
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;
|
||||
|
||||
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)
|
||||
return; /* No sense invalidating pages for new inode since we
|
||||
have not started caching readahead file data yet */
|
||||
return; /* No sense invalidating pages for new inode
|
||||
since have not started caching readahead file
|
||||
data yet */
|
||||
|
||||
if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
|
||||
(local_size == tmp_inode->i_size)) {
|
||||
|
@ -290,7 +306,13 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
|
|||
tmp_inode->i_fop = &cifs_file_direct_ops;
|
||||
else
|
||||
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;
|
||||
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)
|
||||
return; /* No sense invalidating pages for new inode since we
|
||||
|
@ -374,7 +396,8 @@ ffirst_retry:
|
|||
|
||||
rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
|
||||
&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)
|
||||
cifsFile->invalidHandle = FALSE;
|
||||
if((rc == -EOPNOTSUPP) &&
|
||||
|
@ -491,6 +514,30 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
|
|||
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 */
|
||||
/* 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
|
||||
|
@ -507,7 +554,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
|
|||
struct cifsFileInfo * cifsFile = file->private_data;
|
||||
/* 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;
|
||||
|
||||
*ppCurrentEntry = NULL;
|
||||
|
@ -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.entries_in_buffer;
|
||||
/* 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 */
|
||||
cFYI(1,("search backing up - close and restart search"));
|
||||
cifsFile->invalidHandle = TRUE;
|
||||
|
@ -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) &&
|
||||
(rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){
|
||||
cFYI(1,("calling findnext2"));
|
||||
rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf);
|
||||
rc = CIFSFindNext(xid,pTcon,cifsFile->netfid,
|
||||
&cifsFile->srch_inf);
|
||||
if(rc)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -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 +
|
||||
smbCalcSize((struct smb_hdr *)
|
||||
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
|
||||
- cifsFile->srch_inf.entries_in_buffer;
|
||||
pos_in_buf = index_to_find - first_entry_in_buffer;
|
||||
cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
|
||||
current_entry = cifsFile->srch_inf.srch_entries_start;
|
||||
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 ..)
|
||||
skip */
|
||||
rc = cifs_entry_is_dot(current_entry,cifsFile);
|
||||
|
@ -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) {
|
||||
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;
|
||||
} else
|
||||
*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
|
||||
/* dump_cifs_file_struct(file, "end fce ");*/
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -721,7 +770,8 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
|
|||
(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) {
|
||||
cFYI(1,("filldir rc = %d",rc));
|
||||
}
|
||||
|
@ -805,15 +855,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
|||
FreeXid(xid);
|
||||
return -EIO;
|
||||
}
|
||||
/* dump_cifs_file_struct(file, "Begin rdir "); */
|
||||
|
||||
cifs_sb = CIFS_SB(file->f_dentry->d_sb);
|
||||
pTcon = cifs_sb->tcon;
|
||||
if(pTcon == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* cFYI(1,("readdir2 pos: %lld",file->f_pos)); */
|
||||
|
||||
switch ((int) file->f_pos) {
|
||||
case 0:
|
||||
/*if (filldir(direntry, ".", 1, file->f_pos,
|
||||
|
@ -866,7 +913,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
|||
cifsFile->search_resume_name = NULL; */
|
||||
|
||||
/* 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,
|
||||
¤t_entry,&num_to_fill);
|
||||
|
@ -906,14 +952,14 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
|
|||
cifs_save_resume_key(current_entry,cifsFile);
|
||||
break;
|
||||
} else
|
||||
current_entry = nxt_dir_entry(current_entry,end_of_smb);
|
||||
current_entry = nxt_dir_entry(current_entry,
|
||||
end_of_smb);
|
||||
}
|
||||
kfree(tmp_buf);
|
||||
break;
|
||||
} /* end switch */
|
||||
|
||||
rddir2_exit:
|
||||
/* dump_cifs_file_struct(file, "end rdir "); */
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */
|
||||
|
||||
/* RFC 1002 session packet types */
|
||||
|
@ -48,17 +46,17 @@ struct rfc1002_session_packet {
|
|||
__u8 calling_len;
|
||||
__u8 calling_name[32];
|
||||
__u8 scope2; /* null */
|
||||
} session_req;
|
||||
} __attribute__((packed)) session_req;
|
||||
struct {
|
||||
__u32 retarget_ip_addr;
|
||||
__u16 port;
|
||||
} retarget_resp;
|
||||
} __attribute__((packed)) retarget_resp;
|
||||
__u8 neg_ses_resp_error_code;
|
||||
/* POSITIVE_SESSION_RESPONSE packet does not include trailer.
|
||||
SESSION_KEEP_ALIVE packet also does not include a trailer.
|
||||
Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */
|
||||
} trailer;
|
||||
};
|
||||
} __attribute__((packed)) trailer;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Negative Session Response error codes */
|
||||
#define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */
|
||||
|
@ -74,6 +72,3 @@ server netbios name). Currently server names are resolved only via DNS
|
|||
(tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/
|
||||
|
||||
#define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER "
|
||||
|
||||
#pragma pack() /* resume default structure packing */
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,SLAB_KERNEL | SLAB_NOFS);
|
||||
temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
|
||||
SLAB_KERNEL | SLAB_NOFS);
|
||||
if (temp == NULL)
|
||||
return temp;
|
||||
else {
|
||||
|
@ -58,7 +59,9 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
|
|||
temp->pid = current->pid;
|
||||
temp->command = smb_buffer->Command;
|
||||
cFYI(1, ("For smb_command %d", temp->command));
|
||||
do_gettimeofday(&temp->when_sent);
|
||||
/* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
|
||||
/* when mid allocated can be before when sent */
|
||||
temp->when_alloc = jiffies;
|
||||
temp->ses = ses;
|
||||
temp->tsk = current;
|
||||
}
|
||||
|
@ -74,6 +77,9 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
|
|||
static void
|
||||
DeleteMidQEntry(struct mid_q_entry *midEntry)
|
||||
{
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
unsigned long now;
|
||||
#endif
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
midEntry->midState = MID_FREE;
|
||||
list_del(&midEntry->qhead);
|
||||
|
@ -83,6 +89,22 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
|
|||
cifs_buf_release(midEntry->resp_buf);
|
||||
else
|
||||
cifs_small_buf_release(midEntry->resp_buf);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
now = jiffies;
|
||||
/* commands taking longer than one second are indications that
|
||||
something is wrong, unless it is quite a slow link or server */
|
||||
if((now - midEntry->when_alloc) > HZ) {
|
||||
if((cifsFYI & CIFS_TIMER) &&
|
||||
(midEntry->command != SMB_COM_LOCKING_ANDX)) {
|
||||
printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
|
||||
midEntry->command, midEntry->mid);
|
||||
printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
|
||||
now - midEntry->when_alloc,
|
||||
now - midEntry->when_sent,
|
||||
now - midEntry->when_received);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
mempool_free(midEntry, cifs_mid_poolp);
|
||||
}
|
||||
|
||||
|
@ -146,32 +168,37 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
|
|||
Flags2 is converted in SendReceive */
|
||||
|
||||
smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
|
||||
cFYI(1, ("Sending smb of length %d ", smb_buf_length));
|
||||
cFYI(1, ("Sending smb of length %d", smb_buf_length));
|
||||
dump_smb(smb_buffer, len);
|
||||
|
||||
while (len > 0) {
|
||||
rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len);
|
||||
if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
|
||||
i++;
|
||||
if(i > 60) {
|
||||
/* smaller timeout here than send2 since smaller size */
|
||||
/* Although it may not be required, this also is smaller
|
||||
oplock break time */
|
||||
if(i > 12) {
|
||||
cERROR(1,
|
||||
("sends on sock %p stuck for 30 seconds",
|
||||
("sends on sock %p stuck for 7 seconds",
|
||||
ssocket));
|
||||
rc = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
msleep(500);
|
||||
msleep(1 << i);
|
||||
continue;
|
||||
}
|
||||
if (rc < 0)
|
||||
break;
|
||||
else
|
||||
i = 0; /* reset i after each successful send */
|
||||
iov.iov_base += rc;
|
||||
iov.iov_len -= rc;
|
||||
len -= rc;
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
cERROR(1,("Error %d sending data on socket to server.", rc));
|
||||
cERROR(1,("Error %d sending data on socket to server", rc));
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
|
@ -179,26 +206,21 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CIFS_EXPERIMENTAL
|
||||
/* BB finish off this function, adding support for writing set of pages as iovec */
|
||||
/* and also adding support for operations that need to parse the response smb */
|
||||
|
||||
int
|
||||
smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
|
||||
unsigned int smb_buf_length, struct kvec * write_vector
|
||||
/* page list */, struct sockaddr *sin)
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
static int
|
||||
smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
|
||||
struct sockaddr *sin)
|
||||
{
|
||||
int rc = 0;
|
||||
int i = 0;
|
||||
struct msghdr smb_msg;
|
||||
number_of_pages += 1; /* account for SMB header */
|
||||
struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec));
|
||||
unsigned len = smb_buf_length + 4;
|
||||
|
||||
struct smb_hdr *smb_buffer = iov[0].iov_base;
|
||||
unsigned int len = iov[0].iov_len;
|
||||
unsigned int total_len;
|
||||
int first_vec = 0;
|
||||
|
||||
if(ssocket == NULL)
|
||||
return -ENOTSOCK; /* BB eventually add reconnect code here */
|
||||
iov.iov_base = smb_buffer;
|
||||
iov.iov_len = len;
|
||||
|
||||
smb_msg.msg_name = sin;
|
||||
smb_msg.msg_namelen = sizeof (struct sockaddr);
|
||||
|
@ -211,49 +233,80 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer,
|
|||
cifssmb.c and RFC1001 len is converted to bigendian in smb_send
|
||||
Flags2 is converted in SendReceive */
|
||||
|
||||
|
||||
total_len = 0;
|
||||
for (i = 0; i < n_vec; i++)
|
||||
total_len += iov[i].iov_len;
|
||||
|
||||
smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
|
||||
cFYI(1, ("Sending smb of length %d ", smb_buf_length));
|
||||
cFYI(1, ("Sending smb: total_len %d", total_len));
|
||||
dump_smb(smb_buffer, len);
|
||||
|
||||
while (len > 0) {
|
||||
rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages,
|
||||
len);
|
||||
while (total_len) {
|
||||
rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec],
|
||||
n_vec - first_vec, total_len);
|
||||
if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
|
||||
i++;
|
||||
if(i > 60) {
|
||||
if(i >= 14) {
|
||||
cERROR(1,
|
||||
("sends on sock %p stuck for 30 seconds",
|
||||
("sends on sock %p stuck for 15 seconds",
|
||||
ssocket));
|
||||
rc = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
msleep(500);
|
||||
msleep(1 << i);
|
||||
continue;
|
||||
}
|
||||
if (rc < 0)
|
||||
break;
|
||||
iov.iov_base += rc;
|
||||
iov.iov_len -= rc;
|
||||
len -= rc;
|
||||
|
||||
if (rc >= total_len) {
|
||||
WARN_ON(rc > total_len);
|
||||
break;
|
||||
}
|
||||
if(rc == 0) {
|
||||
/* should never happen, letting socket clear before
|
||||
retrying is our only obvious option here */
|
||||
cERROR(1,("tcp sent no data"));
|
||||
msleep(500);
|
||||
continue;
|
||||
}
|
||||
total_len -= rc;
|
||||
/* the line below resets i */
|
||||
for (i = first_vec; i < n_vec; i++) {
|
||||
if (iov[i].iov_len) {
|
||||
if (rc > iov[i].iov_len) {
|
||||
rc -= iov[i].iov_len;
|
||||
iov[i].iov_len = 0;
|
||||
} else {
|
||||
iov[i].iov_base += rc;
|
||||
iov[i].iov_len -= rc;
|
||||
first_vec = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
i = 0; /* in case we get ENOSPC on the next send */
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
cERROR(1,("Error %d sending data on socket to server.", rc));
|
||||
} else {
|
||||
cERROR(1,("Error %d sending data on socket to server", rc));
|
||||
} else
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op)
|
||||
SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
struct kvec *iov, int n_vec, int *pbytes_returned,
|
||||
const int long_op)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned long timeout = 15 * HZ;
|
||||
struct mid_q_entry *midQ = NULL;
|
||||
unsigned int receive_len;
|
||||
unsigned long timeout;
|
||||
struct mid_q_entry *midQ;
|
||||
struct smb_hdr *in_buf = iov[0].iov_base;
|
||||
|
||||
if (ses == NULL) {
|
||||
cERROR(1,("Null smb session"));
|
||||
|
@ -263,14 +316,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
cERROR(1,("Null tcp session"));
|
||||
return -EIO;
|
||||
}
|
||||
if(pbytes_returned == NULL)
|
||||
return -EIO;
|
||||
else
|
||||
*pbytes_returned = 0;
|
||||
|
||||
|
||||
|
||||
if(ses->server->tcpStatus == CIFS_EXITING)
|
||||
if(ses->server->tcpStatus == CifsExiting)
|
||||
return -ENOENT;
|
||||
|
||||
/* Ensure that we do not send more than 50 overlapping requests
|
||||
|
@ -282,11 +329,18 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
} else {
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
while(1) {
|
||||
if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){
|
||||
if(atomic_read(&ses->server->inFlight) >=
|
||||
cifs_max_pending){
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&ses->server->num_waiters);
|
||||
#endif
|
||||
wait_event(ses->server->request_q,
|
||||
atomic_read(&ses->server->inFlight)
|
||||
< cifs_max_pending);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&ses->server->num_waiters);
|
||||
#endif
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
} else {
|
||||
if(ses->server->tcpStatus == CifsExiting) {
|
||||
|
@ -314,17 +368,17 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
|
||||
if (ses->server->tcpStatus == CifsExiting) {
|
||||
rc = -ENOENT;
|
||||
goto cifs_out_label;
|
||||
goto out_unlock2;
|
||||
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
|
||||
cFYI(1,("tcp session dead - return to caller to retry"));
|
||||
rc = -EAGAIN;
|
||||
goto cifs_out_label;
|
||||
goto out_unlock2;
|
||||
} else if (ses->status != CifsGood) {
|
||||
/* check if SMB session is bad because we are setting it up */
|
||||
if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
|
||||
(in_buf->Command != SMB_COM_NEGOTIATE)) {
|
||||
rc = -EAGAIN;
|
||||
goto cifs_out_label;
|
||||
goto out_unlock2;
|
||||
} /* else ok - we are setting up session */
|
||||
}
|
||||
midQ = AllocMidQEntry(in_buf, ses);
|
||||
|
@ -338,27 +392,19 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
up(&ses->server->tcpSem);
|
||||
cERROR(1,
|
||||
("Illegal length, greater than maximum frame, %d ",
|
||||
in_buf->smb_buf_length));
|
||||
DeleteMidQEntry(midQ);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* BB can we sign efficiently in this path? */
|
||||
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
|
||||
/* BB FIXME */
|
||||
/* rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */
|
||||
|
||||
midQ->midState = MID_REQUEST_SUBMITTED;
|
||||
/* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
|
||||
piovec,
|
||||
(struct sockaddr *) &(ses->server->addr.sockAddr));*/
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&ses->server->inSend);
|
||||
#endif
|
||||
rc = smb_send2(ses->server->ssocket, iov, n_vec,
|
||||
(struct sockaddr *) &(ses->server->addr.sockAddr));
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&ses->server->inSend);
|
||||
midQ->when_sent = jiffies;
|
||||
#endif
|
||||
if(rc < 0) {
|
||||
DeleteMidQEntry(midQ);
|
||||
up(&ses->server->tcpSem);
|
||||
|
@ -370,19 +416,138 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
return rc;
|
||||
} else
|
||||
up(&ses->server->tcpSem);
|
||||
cifs_out_label:
|
||||
if(midQ)
|
||||
DeleteMidQEntry(midQ);
|
||||
|
||||
if (long_op == -1)
|
||||
goto cifs_no_response_exit2;
|
||||
else if (long_op == 2) /* writes past end of file can take loong time */
|
||||
timeout = 180 * HZ;
|
||||
else if (long_op == 1)
|
||||
timeout = 45 * HZ; /* should be greater than
|
||||
servers oplock break timeout (about 43 seconds) */
|
||||
else if (long_op > 2) {
|
||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
} else
|
||||
timeout = 15 * HZ;
|
||||
/* wait for 15 seconds or until woken up due to response arriving or
|
||||
due to last connection to this server being unmounted */
|
||||
if (signal_pending(current)) {
|
||||
/* if signal pending do not hold up user for full smb timeout
|
||||
but we still give response a change to complete */
|
||||
timeout = 2 * HZ;
|
||||
}
|
||||
|
||||
/* No user interrupts in wait - wreaks havoc with performance */
|
||||
if(timeout != MAX_SCHEDULE_TIMEOUT) {
|
||||
timeout += jiffies;
|
||||
wait_event(ses->server->response_q,
|
||||
(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
|
||||
time_after(jiffies, timeout) ||
|
||||
((ses->server->tcpStatus != CifsGood) &&
|
||||
(ses->server->tcpStatus != CifsNew)));
|
||||
} else {
|
||||
wait_event(ses->server->response_q,
|
||||
(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
|
||||
((ses->server->tcpStatus != CifsGood) &&
|
||||
(ses->server->tcpStatus != CifsNew)));
|
||||
}
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (midQ->resp_buf) {
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
receive_len = midQ->resp_buf->smb_buf_length;
|
||||
} else {
|
||||
cERROR(1,("No response to cmd %d mid %d",
|
||||
midQ->command, midQ->mid));
|
||||
if(midQ->midState == MID_REQUEST_SUBMITTED) {
|
||||
if(ses->server->tcpStatus == CifsExiting)
|
||||
rc = -EHOSTDOWN;
|
||||
else {
|
||||
ses->server->tcpStatus = CifsNeedReconnect;
|
||||
midQ->midState = MID_RETRY_NEEDED;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc != -EHOSTDOWN) {
|
||||
if(midQ->midState == MID_RETRY_NEEDED) {
|
||||
rc = -EAGAIN;
|
||||
cFYI(1,("marking request for retry"));
|
||||
} else {
|
||||
rc = -EIO;
|
||||
}
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
DeleteMidQEntry(midQ);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
|
||||
receive_len, xid));
|
||||
rc = -EIO;
|
||||
} else { /* rcvd frame is ok */
|
||||
|
||||
if (midQ->resp_buf &&
|
||||
(midQ->midState == MID_RESPONSE_RECEIVED)) {
|
||||
in_buf->smb_buf_length = receive_len;
|
||||
/* BB verify that length would not overrun small buf */
|
||||
memcpy((char *)in_buf + 4,
|
||||
(char *)midQ->resp_buf + 4,
|
||||
receive_len);
|
||||
|
||||
dump_smb(in_buf, 80);
|
||||
/* convert the length into a more usable form */
|
||||
if((receive_len > 24) &&
|
||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
||||
SECMODE_SIGN_ENABLED))) {
|
||||
rc = cifs_verify_signature(in_buf,
|
||||
ses->server->mac_signing_key,
|
||||
midQ->sequence_number+1);
|
||||
if(rc) {
|
||||
cERROR(1,("Unexpected SMB signature"));
|
||||
/* BB FIXME add code to kill session */
|
||||
}
|
||||
}
|
||||
|
||||
*pbytes_returned = in_buf->smb_buf_length;
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
rc = map_smb_to_linux_error(in_buf);
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
if (receive_len >=
|
||||
sizeof (struct smb_hdr) -
|
||||
4 /* do not count RFC1001 header */ +
|
||||
(2 * in_buf->WordCount) + 2 /* bcc */ )
|
||||
BCC(in_buf) = le16_to_cpu(BCC(in_buf));
|
||||
} else {
|
||||
rc = -EIO;
|
||||
cFYI(1,("Bad MID state?"));
|
||||
}
|
||||
}
|
||||
cifs_no_response_exit2:
|
||||
DeleteMidQEntry(midQ);
|
||||
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
out_unlock2:
|
||||
up(&ses->server->tcpSem);
|
||||
/* If not lock req, update # of requests on wire to server */
|
||||
if(long_op < 3) {
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#endif /* CIFS_EXPERIMENTAL */
|
||||
|
||||
int
|
||||
|
@ -419,9 +584,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
if(atomic_read(&ses->server->inFlight) >=
|
||||
cifs_max_pending){
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&ses->server->num_waiters);
|
||||
#endif
|
||||
wait_event(ses->server->request_q,
|
||||
atomic_read(&ses->server->inFlight)
|
||||
< cifs_max_pending);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&ses->server->num_waiters);
|
||||
#endif
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
} else {
|
||||
if(ses->server->tcpStatus == CifsExiting) {
|
||||
|
@ -490,8 +661,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
|
||||
|
||||
midQ->midState = MID_REQUEST_SUBMITTED;
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&ses->server->inSend);
|
||||
#endif
|
||||
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
|
||||
(struct sockaddr *) &(ses->server->addr.sockAddr));
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&ses->server->inSend);
|
||||
midQ->when_sent = jiffies;
|
||||
#endif
|
||||
if(rc < 0) {
|
||||
DeleteMidQEntry(midQ);
|
||||
up(&ses->server->tcpSem);
|
||||
|
@ -506,7 +684,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
if (long_op == -1)
|
||||
goto cifs_no_response_exit;
|
||||
else if (long_op == 2) /* writes past end of file can take loong time */
|
||||
timeout = 300 * HZ;
|
||||
timeout = 180 * HZ;
|
||||
else if (long_op == 1)
|
||||
timeout = 45 * HZ; /* should be greater than
|
||||
servers oplock break timeout (about 43 seconds) */
|
||||
|
@ -540,9 +718,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
spin_lock(&GlobalMid_Lock);
|
||||
if (midQ->resp_buf) {
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf);
|
||||
receive_len = midQ->resp_buf->smb_buf_length;
|
||||
} else {
|
||||
cERROR(1,("No response buffer"));
|
||||
cERROR(1,("No response for cmd %d mid %d",
|
||||
midQ->command, midQ->mid));
|
||||
if(midQ->midState == MID_REQUEST_SUBMITTED) {
|
||||
if(ses->server->tcpStatus == CifsExiting)
|
||||
rc = -EHOSTDOWN;
|
||||
|
@ -610,7 +789,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
BCC(out_buf) = le16_to_cpu(BCC(out_buf));
|
||||
} else {
|
||||
rc = -EIO;
|
||||
cFYI(1,("Bad MID state? "));
|
||||
cERROR(1,("Bad MID state? "));
|
||||
}
|
||||
}
|
||||
cifs_no_response_exit:
|
||||
|
|
|
@ -259,6 +259,8 @@ void __pagevec_release(struct pagevec *pvec)
|
|||
pagevec_reinit(pvec);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(__pagevec_release);
|
||||
|
||||
/*
|
||||
* pagevec_release() for pages which are known to not be on the LRU
|
||||
*
|
||||
|
@ -387,6 +389,7 @@ unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping,
|
|||
return pagevec_count(pvec);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(pagevec_lookup_tag);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue