提交 fca324e7 编写于 作者: L Linus Torvalds

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

......@@ -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
-------------------------------------
......
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
......
version 1.34 April 29, 2005
version 1.37 October 9, 2005
A Partial List of Missing Features
==================================
......@@ -7,14 +7,14 @@ 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
better)
b) Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS
SecurityDescriptors
c) multi-user mounts - multiplexed sessionsetups over single vc
(ie tcp session) - more testing needed
c) Better pam/winbind integration (e.g. to handle uid mapping
better)
d) Kerberos/SPNEGO session setup support - (started)
......@@ -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)
s) Allow remapping of last remaining character (\) to +0xF000 which
(this character is valid for POSIX but not for Windows)
t) Implement O_DIRECT flag on open (already supported on mount)
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
*/
......
此差异已折叠。
......@@ -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,
......
此差异已折叠。
......@@ -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;
cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
temp = (char *) smb_buffer;
if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
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 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} 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 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
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 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
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 */
......
......@@ -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 @@ build_path_from_dentry(struct dentry *direntry)
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));
}
}
......
......@@ -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 */
}
if (tmp->next == NULL) {
cFYI(1, ("File instance %p removed", tmp));
break;
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;
}
}
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, &current_offset);
open_file->netfid,
current_read_size, *poffset,
&bytes_read, &current_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,
......
......@@ -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);
}
}
......
......@@ -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 */
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -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
/*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册