diff -Nau bk/linux-2.5/fs/cifs/CHANGES /home/stevef/bk/linux-2.5cifs/fs/cifs/CHANGES --- bk/linux-2.5/fs/cifs/CHANGES 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/CHANGES 2003-12-08 11:51:31.000000000 -0600 @@ -1,3 +1,37 @@ +Version 0.99 +------------ +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 +the support for CIFS Unix Extensions to be disabled via proc interface. + +Version 0.98 +------------ +Fix hang in commit_write during reconnection of open files under heavy load. +Fix unload_nls oops in a mount failure path. Serialize writes to same socket +which also fixes any possible races when cifs signatures are enabled in SMBs +being sent out of signature sequence number order. + +Version 0.97 +------------ +Fix byte range locking bug (endian problem) causing bad offset and +length. + +Version 0.96 +------------ +Fix oops (in send_sig) caused by CIFS unmount code trying to +wake up the demultiplex thread after it had exited. Do not log +error on harmless oplock release of closed handle. + +Version 0.95 +------------ +Fix unsafe global variable usage and password hash failure on gcc 3.3.1 +Fix problem reconnecting secondary mounts to same server after session +failure. Fix invalid dentry - race in mkdir when directory gets created +by another client between the lookup and mkdir. + Version 0.94 ------------ Fix to list processing in reopen_files. Fix reconnection when server hung diff -Nau bk/linux-2.5/fs/cifs/README /home/stevef/bk/linux-2.5cifs/fs/cifs/README --- bk/linux-2.5/fs/cifs/README 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/README 2003-12-08 11:51:31.000000000 -0600 @@ -1,30 +1,30 @@ -The CIFS VFS support for Linux supports many advanced network filesystem -features such as heirarchical dfs like namespace, hardlinks, locking and more. -It was designed to comply with the SNIA CIFS Technical Reference (which supersedes -the 1992 X/Open SMB Standard) as well as to perform best practice practical -interoperability with Windows 2000, Windows XP, Samba and equivalent +The CIFS VFS support for Linux supports many advanced network filesystem +features such as heirarchical dfs like namespace, hardlinks, locking and more. +It was designed to comply with the SNIA CIFS Technical Reference (which +supersedes the 1992 X/Open SMB Standard) as well as to perform best practice +practical interoperability with Windows 2000, Windows XP, Samba and equivalent servers. -For questions or bug reports please contact sfrench@samba.org (sfrench@us.ibm.com) +For questions or bug reports please contact: + sfrench@samba.org (sfrench@us.ibm.com) Build instructions: ================== For Linux 2.4: -1a) Get the linux kernel source with cifs vfs already in it -from bitkeeper via bk://cifs.bkbits.net/linux-2.4 -or -1b) Get the kernel source (e.g.from http://www.kernel.org) +1) Get the kernel source (e.g.from http://www.kernel.org) and download the cifs vfs source (see the project page at http://us1.samba.org/samba/Linux_CIFS_client.html) and change directory into the top of the kernel directory then patch the kernel (e.g. "patch -p1 < cifs_24.patch") to add the cifs vfs to your kernel configure options if it has not already been added (e.g. current SuSE and UL -users do not need to do not need that patch since the cifs vfs is +users do not need to apply the cifs_24.patch since the cifs vfs is already in the kernel configure menu) and then mkdir linux/fs/cifs and then copy the current cifs vfs files from the cifs download to your kernel build directory e.g. + cp /fs/cifs/* to /fs/cifs + 2) make menuconfig (or make xconfig) 3) select cifs from within the network filesystem choices 4) save and exit @@ -53,56 +53,73 @@ If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on the CIFS VFS web site) copy it to the same directory in which mount.smbfs and -similar files reside (usually /sbin). Although the helper software is required, -mount.cifs is recommended. Eventually the Samba 3.0 utility program "net" -may also be helpful since it may someday provide easier mount syntax for users used -to Windows e.g. - net use -Note that running Winbind on all of your Linux clients is useful in -in mapping Uids and Gids consistently to the proper network user. - -Samba Considerations -==================== -To get the maximum benefit from the CIFS VFS, we recommend using a server that -supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or -Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers. -Note that uid, gid and file permissions will display default values if you do -not have a server that supports the Unix extensions for CIFS (such as Samba 2.2.3 or -later). To enable the Unix CIFS Extensions in the Samba server, add the line: +similar files reside (usually /sbin). Although the helper software is not +required, mount.cifs is recommended. Eventually the Samba 3.0 utility program +"net" may also be helpful since it may someday provide easier mount syntax for +users who are used to Windows e.g. net use +Note that running the Winbind pam/nss module (logon service) on all of your +Linux clients is useful in mapping Uids and Gids consistently across the +domain to the proper network user. The mount.cifs mount helper can be +trivially built from Samba 3.0 or later source e.g. by executing: + + gcc samba/source/client/mount.cifs.c -o mount.cifs + +There is a corresponding manual page for cifs mounting in the Samba 3.0 and +later source tree in docs/manpages/mount.cifs.8 + +Samba Considerations +==================== +To get the maximum benefit from the CIFS VFS, we recommend using a server that +supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or +Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers. +Note that uid, gid and file permissions will display default values if you do +not have a server that supports the Unix extensions for CIFS (such as Samba +2.2.5 or later). To enable the Unix CIFS Extensions in the Samba server, add +the line: + unix extensions = yes -to your smb.conf file on the server. Note that the following smb.conf settings are -also useful (on the Samba server) when the majority of clients are Unix -or Linux: + +to your smb.conf file on the server. Note that the following smb.conf settings +are also useful (on the Samba server) when the majority of clients are Unix or +Linux: + case sensitive = yes - delete readonly = yes -Some administrators also change the "map archive" and the "create mask" parameters -from their default values. Creating special devices (mknod) remotely may require -specifying a mkdev function to Samba. For more information on these see the manual -pages ("man smb.conf") on the Samba server system. Note that the cifs vfs, unlike the -smbfs vfs, does not read the smb.conf on the client system (the few optional settings -are passed in on mount via -o parameters instead). Note that Samba 2.2.7 or later -includes a fix that allows the CIFS VFS to delete open files (required for strict -POSIX compliance). Windows Servers already supported this feature. + delete readonly = yes + +Some administrators also change the "map archive" and the "create mask" +parameters from their default values. Creating special devices (mknod) remotely +may require specifying a mkdev function to Samba. For more information on these +see the manual pages ("man smb.conf") on the Samba server system. Note that the +cifs vfs, unlike the smbfs vfs, does not read the smb.conf on the client system +(the few optional settings are passed in on mount via -o parameters instead). +Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete +open files (required for strict POSIX compliance). Windows Servers already +supported this feature. Use instructions: ================ -Once the CIFS VFS support is built into the kernel or installed as a module (cifs.o), -you can use mount syntax like the following to access Samba or Windows servers: +Once the CIFS VFS support is built into the kernel or installed as a module +(cifs.o), you can use mount syntax like the following to access Samba or Windows +servers: + mount -t cifs //9.53.216.11/e$ /mnt -o user=myname,pass=mypassword + after -o the following cifs vfs specific options are supported: + user= pass= domain= + TCP names (in addition to ip addresses) will be available when the mount helper (mount.cifs) is complete Restrictions ============ -Servers must support the NTLM SMB dialect (which is the most recent, supported by Samba -and Windows NT, 2000 and XP and many other SMB/CIFS servers) and servers must support -either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC 1001/1002 support for -"Netbios-Over-TCP/IP." Neither of these is likely to be a problem as most servers -support this. IPv6 support is planned for the future. +Servers must support the NTLM SMB dialect (which is the most recent, supported +by Samba and Windows NT, 2000 and XP and many other SMB/CIFS servers) and +servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC +1001/1002 support for "Netbios-Over-TCP/IP." Neither of these is likely to be a +problem as most servers support this. IPv6 support is planned for the future. CIFS VFS Mount Options ====================== @@ -145,50 +162,65 @@ Misc /proc/fs/cifs Flags and Debug Info ======================================= Informational pseudo-files: - DebugData Displays information about active CIFS sessions - SimultaneousOps Counter which holds maximum number of +DebugData Displays information about active CIFS sessions +SimultaneousOps Counter which holds maximum number of simultaneous outstanding SMB/CIFS requests. - Stats Lists summary resource usage information +Stats Lists summary resource usage information Configuration pseudo-files: - MultiuserMount If set to one, more than one CIFS session to +MultiuserMount If set to one, more than one CIFS session to the same server ip address can be established if more than one uid accesses the same mount point and if the uids user/password mapping information is available. (default is 0) - PacketSigningEnabled If set to one, cifs packet signing is enabled +PacketSigningEnabled If set to one, cifs packet signing is enabled and will be used if the server requires it. If set to two, cifs packet signing is required even if the server considers packet signing optional. (default 1) - cifsFYI If set to one, additional debug information is +cifsFYI If set to one, additional debug information is logged to the system error log. (default 0) - ExtendedSecurity If set to one, SPNEGO session establishment +ExtendedSecurity If set to one, SPNEGO session establishment is allowed which enables more advanced secure CIFS session establishment (default 0) - NTLMV2Enabled If set to one, more secure password hashes +NTLMV2Enabled If set to one, more secure password hashes are used when the server supports them and when kerberos is not negotiated (default 0) - traceSMB If set to one, debug information is logged to the +traceSMB If set to one, debug information is logged to the system error log with the start of smb requests and responses (default 0) - LookupCacheEnable If set to one, inode information is kept cached +LookupCacheEnable If set to one, inode information is kept cached for one second improving performance of lookups (default 1) - OplockEnabled If set to one, safe distributed caching enabled. +OplockEnabled If set to one, safe distributed caching enabled. (default 1) +LinuxExtensionsEnabled If set to one then the client will attempt to + use the CIFS "UNIX" extensions which are optional + protocol enhancements that allow CIFS servers + to return accurate UID/GID information as well + as support symbolic links. If you use servers + such as Samba that support the CIFS Unix + extensions but do not want to use symbolic link + support and want to map the uid and gid fields + to values supplied at mount (rather than the + actual values, then set this to zero. (deafult 1) + +These experimental features and tracing can be enabled by changing flags in +/proc/fs/cifs (after the cifs module has been installed or built into the +kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable +tracing to the kernel message log type: -These experimental features and tracing can be enabled by changing flags in /proc/fs/cifs -(after the cifs module has been installed or built into the 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 + and for more extensive tracing including the start of smb requests and responses + echo 1 > /proc/fs/cifs/traceSMB -Also note that "cat /proc/fs/cifs/DebugData" will display some information about the -active sessions and the shares that are mounted. NTLMv2 enablement and packet -signing will not work since they the implementation is not quite complete. Do not enable -these flags unless you are doing specific testing. Enabling extended security works to -Windows 2000 Workstations and XP but not to Windows 2000 server or Samba since it does not -usually send "raw NTLMSSP" (instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which -support is not complete in the CIFS VFS yet). + +Also note that "cat /proc/fs/cifs/DebugData" will display some information about +the active sessions and the shares that are mounted. Note: NTLMv2 enablement +will not work since they its implementation is not quite complete yet. +Do not alter these configuration values unless you are doing specific testing. +Enabling extended security works to Windows 2000 Workstations and XP but not to +Windows 2000 server or Samba since it does not usually send "raw NTLMSSP" +(instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not +complete in the CIFS VFS yet). Common subdirectories: bk/linux-2.5/fs/cifs/SCCS and /home/stevef/bk/linux-2.5cifs/fs/cifs/SCCS diff -Nau bk/linux-2.5/fs/cifs/cifs_debug.c /home/stevef/bk/linux-2.5cifs/fs/cifs/cifs_debug.c --- bk/linux-2.5/fs/cifs/cifs_debug.c 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/cifs_debug.c 2003-12-08 11:51:31.000000000 -0600 @@ -88,9 +88,26 @@ i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), ses->serverOS, ses->serverNOS, ses->capabilities,ses->status,ses->server->tcpStatus); buf += length; - if(ses->server) + if(ses->server) { buf += sprintf(buf, "\n\tLocal Users To Same Server: %d SecMode: 0x%x", atomic_read(&ses->server->socketUseCount),ses->server->secMode); + + /* length = sprintf(buf, "\nMIDs: \n"); + buf += length; + + spin_lock(&GlobalMid_Lock); + list_for_each(tmp1, &ses->server->pending_mid_q) { + mid_entry = list_entry(tmp1, struct + mid_q_entry, + qhead); + if(mid_entry) { + length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p\n",mid_entry->midState,mid_entry->command,mid_entry->pid,mid_entry->tsk); + buf += length; + } + } + spin_unlock(&GlobalMid_Lock); */ + } + } read_unlock(&GlobalSMBSeslock); sprintf(buf, "\n"); @@ -127,8 +144,10 @@ buf += sprintf(buf, "\tDISCONNECTED "); } read_unlock(&GlobalSMBSeslock); + length = sprintf(buf, "\n"); buf += length; + *eof = 1; /* BB add code to dump additional info such as TCP session info now */ /* @@ -177,6 +196,9 @@ item_length = sprintf(buf,"Active Operations (MIDs in use): %d\n",midCount.counter); length += item_length; + buf += item_length; + item_length = sprintf(buf,"%d sessions and %d shares reconnected after failure\n",tcpSesReconnectCount.counter,tconInfoReconnectCount.counter); + length += item_length; return length; } @@ -201,6 +223,8 @@ static write_proc_t packet_signing_enabled_write; static read_proc_t quotaEnabled_read; static write_proc_t quotaEnabled_write; +static read_proc_t linuxExtensionsEnabled_read; +static write_proc_t linuxExtensionsEnabled_write; void cifs_proc_init(void) @@ -213,62 +237,67 @@ proc_fs_cifs->owner = THIS_MODULE; create_proc_read_entry("DebugData", 0, proc_fs_cifs, - cifs_debug_data_read, 0); + cifs_debug_data_read, 0); create_proc_read_entry("SimultaneousOps", 0, proc_fs_cifs, - cifs_total_xid_read, 0); + cifs_total_xid_read, 0); create_proc_read_entry("Stats", 0, proc_fs_cifs, - cifs_stats_read, 0); + cifs_stats_read, 0); pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, - cifsFYI_read, 0); + cifsFYI_read, 0); if (pde) pde->write_proc = cifsFYI_write; pde = create_proc_read_entry("traceSMB", 0, proc_fs_cifs, - traceSMB_read, 0); + traceSMB_read, 0); if (pde) pde->write_proc = traceSMB_write; pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs, - oplockEnabled_read, 0); + oplockEnabled_read, 0); if (pde) pde->write_proc = oplockEnabled_write; - pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs, - quotaEnabled_read, 0); - if (pde) - pde->write_proc = quotaEnabled_write; + pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs, + quotaEnabled_read, 0); + if (pde) + pde->write_proc = quotaEnabled_write; + + pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, + linuxExtensionsEnabled_read, 0); + if (pde) + pde->write_proc = linuxExtensionsEnabled_write; pde = create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs, - multiuser_mount_read, 0); + multiuser_mount_read, 0); if (pde) pde->write_proc = multiuser_mount_write; pde = create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs, - extended_security_read, 0); + extended_security_read, 0); if (pde) pde->write_proc = extended_security_write; pde = - create_proc_read_entry("LookupCacheEnable", 0, proc_fs_cifs, - lookupFlag_read, 0); + create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, + lookupFlag_read, 0); if (pde) pde->write_proc = lookupFlag_write; pde = create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, - ntlmv2_enabled_read, 0); + ntlmv2_enabled_read, 0); if (pde) pde->write_proc = ntlmv2_enabled_write; pde = create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, - packet_signing_enabled_read, 0); + packet_signing_enabled_read, 0); if (pde) pde->write_proc = packet_signing_enabled_write; } @@ -283,12 +312,15 @@ remove_proc_entry("cifsFYI", proc_fs_cifs); remove_proc_entry("TraceSMB", proc_fs_cifs); remove_proc_entry("SimultaneousOps", proc_fs_cifs); - remove_proc_entry("TotalOps", proc_fs_cifs); + remove_proc_entry("Stats", proc_fs_cifs); remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("OplockEnabled", proc_fs_cifs); remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); remove_proc_entry("ExtendedSecurity",proc_fs_cifs); remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); + remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); + remove_proc_entry("QuotaEnabled",proc_fs_cifs); + remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); remove_proc_entry("cifs", proc_root_fs); } @@ -410,6 +442,46 @@ return count; } +static int +linuxExtensionsEnabled_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + len = sprintf(page, "%d\n", linuxExtEnabled); +/* could also check if quotas are enabled in kernel + as a whole first */ + len -= off; + *start = page + off; + + if (len > count) + len = count; + else + *eof = 1; + + if (len < 0) + len = 0; + + return len; +} +static int +linuxExtensionsEnabled_write(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char c; + int rc; + + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + linuxExtEnabled = 0; + else if (c == '1' || c == 'y' || c == 'Y') + linuxExtEnabled = 1; + + return count; +} + static int lookupFlag_read(char *page, char **start, off_t off, diff -Nau bk/linux-2.5/fs/cifs/cifsfs.c /home/stevef/bk/linux-2.5cifs/fs/cifs/cifsfs.c --- bk/linux-2.5/fs/cifs/cifsfs.c 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/cifsfs.c 2003-12-08 11:51:31.000000000 -0600 @@ -52,6 +52,7 @@ int traceSMB = 0; unsigned int oplockEnabled = 1; unsigned int quotaEnabled = 0; +unsigned int linuxExtEnabled = 1; unsigned int lookupCacheEnabled = 1; unsigned int multiuser_mount = 0; unsigned int extended_security = 0; @@ -81,6 +82,9 @@ cifs_sb = CIFS_SB(sb); if(cifs_sb == NULL) return -ENOMEM; + else + memset(cifs_sb,0,sizeof(struct cifs_sb_info)); + rc = cifs_mount(sb, cifs_sb, data, devname); @@ -583,7 +587,7 @@ do { set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(39*HZ); + schedule_timeout(1*HZ); spin_lock(&GlobalMid_Lock); if(list_empty(&GlobalOplock_Q)) { spin_unlock(&GlobalMid_Lock); @@ -597,18 +601,29 @@ netfid = oplock_item->netfid; spin_unlock(&GlobalMid_Lock); DeleteOplockQEntry(oplock_item); - if (S_ISREG(inode->i_mode)) + if (S_ISREG(inode->i_mode)) { rc = filemap_fdatawrite(inode->i_mapping); - else + if(CIFS_I(inode)->clientCanCacheRead == 0) + invalidate_remote_inode(inode); + } else rc = 0; if (rc) CIFS_I(inode)->write_behind_rc = rc; cFYI(1,("Oplock flush inode %p rc %d",inode,rc)); - rc = CIFSSMBLock(0, pTcon, netfid, - 0 /* len */ , 0 /* offset */, 0, - 0, LOCKING_ANDX_OPLOCK_RELEASE, - 0 /* wait flag */); - cFYI(1,("Oplock release rc = %d ",rc)); + + /* releasing a stale oplock after recent reconnection + of smb session using a now incorrect file + handle is not a data integrity issue but do + not bother sending an oplock release if session + to server still is disconnected since oplock + already released by the server in that case */ + if(pTcon->tidStatus != CifsNeedReconnect) { + rc = CIFSSMBLock(0, pTcon, netfid, + 0 /* len */ , 0 /* offset */, 0, + 0, LOCKING_ANDX_OPLOCK_RELEASE, + 0 /* wait flag */); + cFYI(1,("Oplock release rc = %d ",rc)); + } } else spin_unlock(&GlobalMid_Lock); } @@ -632,6 +647,9 @@ */ atomic_set(&sesInfoAllocCount, 0); atomic_set(&tconInfoAllocCount, 0); + atomic_set(&tcpSesReconnectCount, 0); + atomic_set(&tconInfoReconnectCount, 0); + atomic_set(&bufAllocCount, 0); atomic_set(&midCount, 0); GlobalCurrentXid = 0; diff -Nau bk/linux-2.5/fs/cifs/cifsglob.h /home/stevef/bk/linux-2.5cifs/fs/cifs/cifsglob.h --- bk/linux-2.5/fs/cifs/cifsglob.h 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/cifsglob.h 2003-12-08 11:51:31.000000000 -0600 @@ -55,6 +55,10 @@ #define TRUE 1 #endif +#ifndef XATTR_DOS_ATTRIB +#define XATTR_DOS_ATTRIB "user.DOSATTRIB" +#endif + /* * This information is kept on every Server we know about. * @@ -175,13 +179,14 @@ struct cifsSesInfo *ses; /* pointer to session associated with */ char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */ char *nativeFileSystem; - __u16 tid; /* The 2 byte transaction id */ + __u16 tid; /* The 2 byte tree id */ __u16 Flags; /* optional support bits */ enum statusEnum tidStatus; - atomic_t useCount; /* how many mounts (explicit or implicit refer to this share */ + atomic_t useCount; /* how many mounts (explicit or implicit) to this share */ FILE_SYSTEM_DEVICE_INFO fsDevInfo; - FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* note file system name may be truncated - but very unlikely */ + FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ FILE_SYSTEM_UNIX_INFO fsUnixInfo; + int retry:1; /* BB add field for back pointer to sb struct? */ }; @@ -213,6 +218,7 @@ int closePend:1; /* file is marked to close */ int emptyDir:1; int invalidHandle:1; /* file closed via session abend */ + struct semaphore fh_sem; /* prevents reopen race after dead ses*/ char * search_resume_name; unsigned int resume_name_length; __u32 resume_key; @@ -274,6 +280,7 @@ #define MID_REQUEST_ALLOCATED 1 #define MID_REQUEST_SUBMITTED 2 #define MID_RESPONSE_RECEIVED 4 +#define MID_RETRY_NEEDED 8 /* session closed while this request out */ struct servers_not_supported { /* @z4a */ struct servers_not_supported *next1; /* @z4a */ @@ -313,7 +320,7 @@ * ---------- * sesSem operations on smb session * tconSem operations on tree connection - * i_sem inode operations + * fh_sem file handle reconnection operations * ****************************************************************************/ @@ -358,6 +365,9 @@ GLOBAL_EXTERN atomic_t sesInfoAllocCount; GLOBAL_EXTERN atomic_t tconInfoAllocCount; +GLOBAL_EXTERN atomic_t tcpSesReconnectCount; +GLOBAL_EXTERN atomic_t tconInfoReconnectCount; + /* Various Debug counters to remove someday (BB) */ GLOBAL_EXTERN atomic_t bufAllocCount; GLOBAL_EXTERN atomic_t midCount; @@ -374,4 +384,6 @@ with more secure ntlmssp2 challenge/resp */ GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ +GLOBAL_EXTERN unsigned int linuxExtEnabled; /* enable Linux/Unix CIFS extensions */ + diff -Nau bk/linux-2.5/fs/cifs/cifspdu.h /home/stevef/bk/linux-2.5cifs/fs/cifs/cifspdu.h --- bk/linux-2.5/fs/cifs/cifspdu.h 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/cifspdu.h 2003-12-08 11:51:31.000000000 -0600 @@ -727,8 +727,10 @@ typedef struct locking_andx_range { __u16 Pid; __u16 Pad; - __u64 Offset; - __u64 Length; + __u32 OffsetHigh; + __u32 OffsetLow; + __u32 LengthHigh; + __u32 LengthLow; } LOCKING_ANDX_RANGE; #define LOCKING_ANDX_SHARED_LOCK 0x01 diff -Nau bk/linux-2.5/fs/cifs/cifsproto.h /home/stevef/bk/linux-2.5cifs/fs/cifs/cifsproto.h --- bk/linux-2.5/fs/cifs/cifsproto.h 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/cifsproto.h 2003-12-08 11:51:31.000000000 -0600 @@ -75,7 +75,6 @@ const unsigned char *search_path, struct super_block *sb); -extern int reopen_files(struct cifsTconInfo *, struct nls_table *); extern int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info); extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses); diff -Nau bk/linux-2.5/fs/cifs/cifssmb.c /home/stevef/bk/linux-2.5cifs/fs/cifs/cifssmb.c --- bk/linux-2.5/fs/cifs/cifssmb.c 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/cifssmb.c 2003-12-08 11:51:31.000000000 -0600 @@ -21,7 +21,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */ + /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */ + /* These are mostly routines that operate on a pathname, or on a tree id */ + /* (mounted volume), but there are eight handle based routines which must be */ + /* treated slightly different for reconnection purposes since we never want */ + /* to reuse a stale file handle and the caller knows the file handle */ #include #include @@ -37,11 +41,30 @@ int index; char *name; } protocols[] = { - { - CIFS_PROT, "\2NT LM 0.12"}, { - BAD_PROT, "\2"} + {CIFS_PROT, "\2NT LM 0.12"}, + {BAD_PROT, "\2"} }; + +/* Mark as invalid, all open files on tree connections since they + were closed when session to server was lost */ +void mark_open_files_invalid(struct cifsTconInfo * pTcon) +{ + struct cifsFileInfo *open_file = NULL; + struct list_head * tmp; + struct list_head * tmp1; + +/* list all files open on tree connection and mark them invalid */ + write_lock(&GlobalSMBSeslock); + list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { + open_file = list_entry(tmp,struct cifsFileInfo, tlist); + if(open_file) { + open_file->invalidHandle = TRUE; + } + } + write_unlock(&GlobalSMBSeslock); +} + int smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, void **request_buf /* returned */ , @@ -49,20 +72,70 @@ { int rc = 0; - if(tcon && (tcon->tidStatus == CifsNeedReconnect)) { - rc = -EIO; - if(tcon->ses) { - struct nls_table *nls_codepage = load_nls_default(); + /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so + check for tcp and smb session status done differently + for those three - in the calling routine */ + if(tcon) { + if((tcon->ses) && (tcon->ses->server)){ + struct nls_table *nls_codepage; + /* Give Demultiplex thread up to 10 seconds to + reconnect, should be greater than cifs socket + timeout which is 7 seconds */ + while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { + wait_event_interruptible_timeout(tcon->ses->server->response_q, + (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ); + if(tcon->ses->server->tcpStatus == CifsNeedReconnect) { + /* on "soft" mounts we wait once */ + if((tcon->retry == FALSE) || + (tcon->ses->status == CifsExiting)) { + cFYI(1,("gave up waiting on reconnect in smb_init")); + return -EHOSTDOWN; + } /* else "hard" mount - keep retrying until + process is killed or server comes back up */ + } else /* TCP session is reestablished now */ + break; + + } + + nls_codepage = load_nls_default(); + /* need to prevent multiple threads trying to + simultaneously reconnect the same SMB session */ + down(&tcon->ses->sesSem); if(tcon->ses->status == CifsNeedReconnect) rc = setup_session(0, tcon->ses, nls_codepage); - if(!rc) { + if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { + mark_open_files_invalid(tcon); rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, nls_codepage); + up(&tcon->ses->sesSem); + if(rc == 0) + atomic_inc(&tconInfoReconnectCount); + cFYI(1, ("reconnect tcon rc = %d", rc)); - if(!rc) - reopen_files(tcon,nls_codepage); + /* Removed call to reopen open files here - + it is safer (and faster) to reopen files + one at a time as needed in read and write */ + + /* Check if handle based operation so we + know whether we can continue or not without + returning to caller to reset file handle */ + switch(smb_command) { + case SMB_COM_READ_ANDX: + case SMB_COM_WRITE_ANDX: + case SMB_COM_CLOSE: + case SMB_COM_FIND_CLOSE2: + case SMB_COM_LOCKING_ANDX: { + unload_nls(nls_codepage); + return -EAGAIN; + } + } + } else { + up(&tcon->ses->sesSem); } unload_nls(nls_codepage); + + } else { + return -EIO; } } if(rc) @@ -98,7 +171,6 @@ rc = -EIO; return rc; } - rc = smb_init(SMB_COM_NEGOTIATE, 0, 0 /* no tcon yet */ , (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -218,12 +290,19 @@ return -EBUSY; } + /* No need to return error on this operation if tid invalidated and + closed on server already e.g. due to tcp session crashing */ + if(tcon->tidStatus == CifsNeedReconnect) { + up(&tcon->tconSem); + return 0; + } + /* BB remove (from server) list of shares - but with smp safety BB */ /* BB is ses active - do we need to check here - but how? BB */ - if((tcon->ses == 0) || (tcon->ses->server == 0)) { - up(&tcon->tconSem); - return -EIO; - } + if((tcon->ses == 0) || (tcon->ses->server == 0)) { + up(&tcon->tconSem); + return -EIO; + } rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **) &smb_buffer, (void **) &smb_buffer_response); @@ -239,6 +318,12 @@ if (smb_buffer) buf_release(smb_buffer); up(&tcon->tconSem); + + /* No need to return error on this operation if tid invalidated and + closed on server already e.g. due to tcp session crashing */ + if (rc == -EAGAIN) + rc = 0; + return rc; } @@ -251,9 +336,8 @@ int length; cFYI(1, ("In SMBLogoff for session disconnect")); - if (ses) - down(&ses->sesSem); /* check this sem more places */ + down(&ses->sesSem); else return -EIO; @@ -287,6 +371,12 @@ if (pSMB) buf_release(pSMB); up(&ses->sesSem); + + /* if session dead then we do not need to do ulogoff, + since server closed smb session, no sense reporting + error */ + if (rc == -EAGAIN) + rc = 0; return rc; } @@ -300,6 +390,7 @@ int bytes_returned; int name_len; +DelFileRetry: rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -330,6 +421,9 @@ } if (pSMB) buf_release(pSMB); + if (rc == -EAGAIN) + goto DelFileRetry; + return rc; } @@ -344,7 +438,7 @@ int name_len; cFYI(1, ("In CIFSSMBRmDir")); - +RmDirRetry: rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -373,6 +467,8 @@ } if (pSMB) buf_release(pSMB); + if (rc == -EAGAIN) + goto RmDirRetry; return rc; } @@ -387,7 +483,7 @@ int name_len; cFYI(1, ("In CIFSSMBMkDir")); - +MkDirRetry: rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -416,7 +512,8 @@ } if (pSMB) buf_release(pSMB); - + if (rc == -EAGAIN) + goto MkDirRetry; return rc; } @@ -433,6 +530,7 @@ int bytes_returned; int name_len; +openRetry: rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -502,7 +600,8 @@ } if (pSMB) buf_release(pSMB); - + if (rc == -EAGAIN) + goto openRetry; return rc; } @@ -571,6 +670,9 @@ else *buf = (char *)pSMB; } + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ return rc; } @@ -625,6 +727,9 @@ if (pSMB) buf_release(pSMB); + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; } @@ -639,9 +744,9 @@ LOCK_RSP *pSMBr = NULL; int bytes_returned; int timeout = 0; + __u64 temp; cFYI(1, ("In CIFSSMBLock")); - rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -658,8 +763,12 @@ pSMB->Fid = smb_file_id; /* netfid stays le */ pSMB->Locks[0].Pid = cpu_to_le16(current->tgid); - pSMB->Locks[0].Length = cpu_to_le64(len); - pSMB->Locks[0].Offset = cpu_to_le64(offset); + temp = cpu_to_le64(len); + pSMB->Locks[0].LengthLow = (__u32)(len & 0xFFFFFFFF); + pSMB->Locks[0].LengthHigh = (__u32)(len>>32); + temp = cpu_to_le64(offset); + pSMB->Locks[0].OffsetLow = (__u32)(offset & 0xFFFFFFFF); + pSMB->Locks[0].OffsetHigh = (__u32)(offset>>32); pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE); pSMB->hdr.smb_buf_length += pSMB->ByteCount; pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); @@ -673,6 +782,8 @@ if (pSMB) buf_release(pSMB); + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ return rc; } @@ -685,8 +796,11 @@ int bytes_returned; cFYI(1, ("In CIFSSMBClose")); +/* do not retry on dead session on close */ rc = smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB, (void **) &pSMBr); + if(rc == -EAGAIN) + return 0; if (rc) return rc; @@ -701,6 +815,10 @@ if (pSMB) buf_release(pSMB); + /* Since session is dead, file will be closed on server already */ + if(rc == -EAGAIN) + rc = 0; + return rc; } @@ -716,7 +834,7 @@ int name_len, name_len2; cFYI(1, ("In CIFSSMBRename")); - +renameRetry: rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -768,23 +886,25 @@ if (pSMB) buf_release(pSMB); + if (rc == -EAGAIN) + goto renameRetry; + return rc; } int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, int netfid, char * target_name, const struct nls_table * nls_codepage) { - struct smb_com_transaction2_sfi_req *pSMB = NULL; - struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; + struct smb_com_transaction2_sfi_req *pSMB = NULL; + struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; struct set_file_rename * rename_info; - char *data_offset; + char *data_offset; char dummy_string[30]; - int rc = 0; - int bytes_returned = 0; + int rc = 0; + int bytes_returned = 0; int len_of_str; cFYI(1, ("Rename to File by handle")); - rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -841,6 +961,10 @@ if (pSMB) buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; } @@ -859,7 +983,7 @@ int bytes_returned = 0; cFYI(1, ("In Symlink Unix style")); - +createSymLinkRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -930,6 +1054,10 @@ if (pSMB) buf_release(pSMB); + + if (rc == -EAGAIN) + goto createSymLinkRetry; + return rc; } @@ -947,7 +1075,7 @@ int bytes_returned = 0; cFYI(1, ("In Create Hard link Unix style")); - +createHardLinkRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1015,6 +1143,9 @@ if (pSMB) buf_release(pSMB); + if (rc == -EAGAIN) + goto createHardLinkRetry; + return rc; } @@ -1030,6 +1161,7 @@ int name_len, name_len2; cFYI(1, ("In CIFSCreateHardLink")); +winCreateHardLinkRetry: rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -1082,6 +1214,8 @@ } if (pSMB) buf_release(pSMB); + if (rc == -EAGAIN) + goto winCreateHardLinkRetry; return rc; } @@ -1100,6 +1234,8 @@ int name_len; cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName)); + +querySymLinkRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1175,6 +1311,8 @@ } if (pSMB) buf_release(pSMB); + if (rc == -EAGAIN) + goto querySymLinkRetry; return rc; } @@ -1257,6 +1395,10 @@ } if (pSMB) buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; } @@ -1274,6 +1416,7 @@ int name_len; cFYI(1, ("In QPathInfo path %s", searchName)); +QPathInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1335,6 +1478,9 @@ } if (pSMB) buf_release(pSMB); + if (rc == -EAGAIN) + goto QPathInfoRetry; + return rc; } @@ -1352,6 +1498,7 @@ int name_len; cFYI(1, ("In QPathInfo (Unix) the path %s", searchName)); +UnixQPathInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1414,6 +1561,9 @@ } if (pSMB) buf_release(pSMB); + if (rc == -EAGAIN) + goto UnixQPathInfoRetry; + return rc; } @@ -1430,6 +1580,7 @@ int name_len; cFYI(1, ("In FindUnique")); +findUniqueRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1488,6 +1639,9 @@ } if (pSMB) buf_release(pSMB); + if (rc == -EAGAIN) + goto findUniqueRetry; + return rc; } @@ -1507,6 +1661,7 @@ int name_len; cFYI(1, ("In FindFirst")); +findFirstRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1591,6 +1746,10 @@ } if (pSMB) buf_release(pSMB); + + if (rc == -EAGAIN) + goto findFirstRetry; + return rc; } @@ -1608,6 +1767,7 @@ int bytes_returned; cFYI(1, ("In FindNext")); + if(resume_file_name == NULL) { return -EIO; } @@ -1691,6 +1851,10 @@ } if (pSMB) buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; } @@ -1701,10 +1865,14 @@ FINDCLOSE_REQ *pSMB = NULL; CLOSE_RSP *pSMBr = NULL; int bytes_returned; - cFYI(1, ("In CIFSSMBFindClose")); + cFYI(1, ("In CIFSSMBFindClose")); rc = smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **) &pSMB, (void **) &pSMBr); + /* no sense returning error if session restarted + file handle has been closed */ + if(rc == -EAGAIN) + return 0; if (rc) return rc; @@ -1718,6 +1886,10 @@ if (pSMB) buf_release(pSMB); + /* Since session is dead, search handle closed on server already */ + if (rc == -EAGAIN) + rc = 0; + return rc; } @@ -1743,7 +1915,7 @@ cFYI(1, ("In GetDFSRefer the path %s", searchName)); if (ses == NULL) return -ENODEV; - +getDFSRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, 0, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1875,6 +2047,10 @@ } if (pSMB) buf_release(pSMB); + + if (rc == -EAGAIN) + goto getDFSRetry; + return rc; } @@ -1890,7 +2066,7 @@ int bytes_returned = 0; cFYI(1, ("In QFSInfo")); - +QFSInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1952,6 +2128,10 @@ } if (pSMB) buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSInfoRetry; + return rc; } @@ -1967,6 +2147,7 @@ int bytes_returned = 0; cFYI(1, ("In QFSAttributeInfo")); +QFSAttributeRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2014,6 +2195,10 @@ } if (pSMB) buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSAttributeRetry; + return rc; } @@ -2029,7 +2214,7 @@ int bytes_returned = 0; cFYI(1, ("In QFSDeviceInfo")); - +QFSDeviceRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2079,6 +2264,11 @@ } if (pSMB) buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSDeviceRetry; + + return rc; } @@ -2094,6 +2284,7 @@ int bytes_returned = 0; cFYI(1, ("In QFSUnixInfo")); +QFSUnixRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2141,6 +2332,11 @@ } if (pSMB) buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSUnixRetry; + + return rc; } @@ -2162,7 +2358,7 @@ int bytes_returned = 0; cFYI(1, ("In SetEOF")); - +SetEOFRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2233,6 +2429,10 @@ if (pSMB) buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetEOFRetry; + return rc; } @@ -2249,7 +2449,6 @@ __u32 tmp; cFYI(1, ("SetFileSize (via SetFileInfo)")); - rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2319,6 +2518,10 @@ if (pSMB) buf_release(pSMB); + + /* Note: On -EAGAIN error only caller can retry on handle based calls + since file handle passed in no longer valid */ + return rc; } @@ -2335,6 +2538,7 @@ cFYI(1, ("In SetTimes")); +SetTimesRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2393,6 +2597,10 @@ if (pSMB) buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetTimesRetry; + return rc; } @@ -2409,7 +2617,7 @@ FILE_UNIX_BASIC_INFO *data_offset; cFYI(1, ("In SetUID/GID/Mode")); - +setPermsRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2471,5 +2679,7 @@ if (pSMB) buf_release(pSMB); + if (rc == -EAGAIN) + goto setPermsRetry; return rc; } diff -Nau bk/linux-2.5/fs/cifs/connect.c /home/stevef/bk/linux-2.5cifs/fs/cifs/connect.c --- bk/linux-2.5/fs/cifs/connect.c 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/connect.c 2003-12-08 11:51:31.000000000 -0600 @@ -58,7 +58,8 @@ gid_t linux_gid; mode_t file_mode; mode_t dir_mode; - int rw; + int rw:1; + int retry:1; unsigned int rsize; unsigned int wsize; unsigned int sockopt; @@ -84,6 +85,7 @@ struct list_head *tmp; struct cifsSesInfo *ses; struct cifsTconInfo *tcon; + struct mid_q_entry * mid_entry; if(server->tcpStatus == CifsExiting) return rc; @@ -123,6 +125,23 @@ server->ssocket = NULL; } + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct + mid_q_entry, + qhead); + if(mid_entry) { + if(mid_entry->midState == MID_REQUEST_SUBMITTED) { + /* Mark other intransit requests as needing retry so + we do not immediately mark the session bad again + (ie after we reconnect below) as they timeout too */ + mid_entry->midState = MID_RETRY_NEEDED; + } + } + } + spin_unlock(&GlobalMid_Lock); + + while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) { rc = ipv4_connect(&server->sockAddr, &server->ssocket); @@ -130,6 +149,7 @@ set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(3 * HZ); } else { + atomic_inc(&tcpSesReconnectCount); server->tcpStatus = CifsGood; wake_up(&server->response_q); } @@ -193,6 +213,7 @@ } else if (server->tcpStatus == CifsNeedReconnect) { cFYI(1,("Reconnecting after server stopped responding")); cifs_reconnect(server); + cFYI(1,("call to reconnect done")); csocket = server->ssocket; continue; } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { @@ -201,6 +222,15 @@ tcpStatus CifsNeedReconnect if server hung */ continue; } else if (length <= 0) { + if(server->tcpStatus == CifsNew) { + cFYI(1,("tcp session abended prematurely (after SMBnegprot)")); + /* some servers kill tcp session rather than returning + smb negprot error in which case reconnecting here is + not going to help - return error to mount */ + server->tcpStatus = CifsExiting; + break; + } + cFYI(1,("Reconnecting after unexpected rcvmsg error ")); cifs_reconnect(server); csocket = server->ssocket; @@ -286,7 +316,7 @@ mid_q_entry, qhead); - if (mid_entry->mid == smb_buffer->Mid) { + if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) { cFYI(1, (" Mid 0x%x matched - waking up ",mid_entry->mid)); task_to_wake = mid_entry->tsk; @@ -302,6 +332,7 @@ wake_up_process(task_to_wake); } else if (is_valid_oplock_break(smb_buffer) == FALSE) { cERROR(1, ("No task to wake, unknown frame rcvd!")); + cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); } } } else { @@ -317,9 +348,10 @@ } } /* BB add code to lock SMB sessions while releasing */ + server->tsk = NULL; if(server->ssocket) { sock_release(csocket); - server->ssocket = NULL; + server->ssocket = NULL; } set_fs(temp_fs); if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ @@ -364,6 +396,7 @@ /* 2767 perms indicate mandatory locking support */ vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); + /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ vol->rw = TRUE; if (!options) @@ -508,6 +541,14 @@ vol->rw = TRUE; } else if (strnicmp(data, "ro", 2) == 0) { vol->rw = FALSE; + } else if (strnicmp(data, "hard", 4) == 0) { + vol->retry = 1; + } else if (strnicmp(data, "soft", 4) == 0) { + vol->retry = 0; + } else if (strnicmp(data, "nohard", 6) == 0) { + vol->retry = 0; + } else if (strnicmp(data, "nosoft", 6) == 0) { + vol->retry = 1; } else printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data); } @@ -673,9 +714,19 @@ int ntlmv2_flag = FALSE; /* what if server changes its buffer size after dropping the session? */ - if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ + if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { rc = CIFSSMBNegotiate(xid, pSesInfo); + if(rc == -EAGAIN) /* retry only once on 1st time connection */ { + rc = CIFSSMBNegotiate(xid, pSesInfo); + if(rc == -EAGAIN) + rc = -EHOSTDOWN; + } + if(rc == 0) + pSesInfo->server->tcpStatus = CifsGood; + } pSesInfo->capabilities = pSesInfo->server->capabilities; + if(linuxExtEnabled == 0) + pSesInfo->capabilities &= (~CAP_UNIX); pSesInfo->sequence_number = 0; if (!rc) { cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", @@ -773,18 +824,17 @@ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof (struct sockaddr_in),0); - if (rc >= 0) { - return rc; - } } - /* do not retry on the same port we just failed on */ - if(psin_server->sin_port != htons(CIFS_PORT)) { - psin_server->sin_port = htons(CIFS_PORT); + if(rc < 0) { + /* do not retry on the same port we just failed on */ + if(psin_server->sin_port != htons(CIFS_PORT)) { + psin_server->sin_port = htons(CIFS_PORT); - rc = (*csocket)->ops->connect(*csocket, + rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof (struct sockaddr_in),0); + } } if (rc < 0) { psin_server->sin_port = htons(RFC1001_PORT); @@ -801,7 +851,8 @@ /* Eventually check for other socket options to change from the default. sock_setsockopt not used because it expects user space buffer */ - (*csocket)->sk->sk_rcvtimeo = 8 * HZ; + (*csocket)->sk->sk_rcvtimeo = 7 * HZ; + cFYI(1,("timeout addr: %p ",&((*csocket)->sk->sk_rcvtimeo))); /* BB removeme BB */ return rc; } @@ -951,7 +1002,8 @@ srvTcp->ssocket = csocket; init_waitqueue_head(&srvTcp->response_q); INIT_LIST_HEAD(&srvTcp->pending_mid_q); - srvTcp->tcpStatus = CifsGood; + srvTcp->tcpStatus = CifsNew; + init_MUTEX(&srvTcp->tcpSem); kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp, CLONE_FS | CLONE_FILES | CLONE_VM); } @@ -982,8 +1034,9 @@ strncpy(pSesInfo->domainName, volume_info.domainname,MAX_USERNAME_SIZE); pSesInfo->linux_uid = volume_info.linux_uid; - + down(&pSesInfo->sesSem); rc = setup_session(xid,pSesInfo, cifs_sb->local_nls); + up(&pSesInfo->sesSem); if(!rc) atomic_inc(&srvTcp->socketUseCount); } @@ -1013,6 +1066,11 @@ volume_info.username); if (tcon) { cFYI(1, ("Found match on UNC path ")); + /* we can have only one retry value for a connection + to a share so for resources mounted more than once + to the same server share the last value passed in + for the retry flag is used */ + tcon->retry = volume_info.retry; } else { tcon = tconInfoAlloc(); if (tcon == NULL) @@ -1039,8 +1097,10 @@ tcon, cifs_sb->local_nls); cFYI(1, ("CIFS Tcon rc = %d", rc)); } - if (!rc) + if (!rc) { atomic_inc(&pSesInfo->inUse); + tcon->retry = volume_info.retry; + } } } } @@ -1064,8 +1124,6 @@ CIFSSMBLogoff(xid, pSesInfo); if(pSesInfo->server->tsk) send_sig(SIGKILL,pSesInfo->server->tsk,1); - else - cFYI(1,("Can not wake captive thread on cleanup of failed mount")); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ / 4); /* give captive thread time to exit */ } else diff -Nau bk/linux-2.5/fs/cifs/dir.c /home/stevef/bk/linux-2.5cifs/fs/cifs/dir.c --- bk/linux-2.5/fs/cifs/dir.c 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/dir.c 2003-12-08 11:51:31.000000000 -0600 @@ -220,6 +220,7 @@ pCifsFile->pInode = newinode; pCifsFile->invalidHandle = FALSE; pCifsFile->closePend = FALSE; + init_MUTEX(&pCifsFile->fh_sem); /* pCifsFile->pfile = file; */ /* put in at open time */ write_lock(&GlobalSMBSeslock); list_add(&pCifsFile->tlist,&pTcon->openFileList); diff -Nau bk/linux-2.5/fs/cifs/file.c /home/stevef/bk/linux-2.5cifs/fs/cifs/file.c --- bk/linux-2.5/fs/cifs/file.c 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/file.c 2003-12-08 11:51:31.000000000 -0600 @@ -142,6 +142,7 @@ pCifsFile = (struct cifsFileInfo *) file->private_data; pCifsFile->netfid = netfid; pCifsFile->pid = current->pid; + init_MUTEX(&pCifsFile->fh_sem); pCifsFile->pfile = file; /* needed for writepage */ pCifsFile->pInode = inode; pCifsFile->invalidHandle = FALSE; @@ -210,152 +211,103 @@ static int cifs_reopen_file(struct inode *inode, struct file *file) { - int rc = -EACCES; - int xid, oplock; - struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; - struct cifsFileInfo *pCifsFile; - struct cifsInodeInfo *pCifsInode; - char *full_path = NULL; - int desiredAccess = 0x20197; - int disposition = FILE_OPEN; - __u16 netfid; - FILE_ALL_INFO * buf = NULL; - - xid = GetXid(); - - cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; - - full_path = build_path_from_dentry(file->f_dentry); - - cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path)); - if ((file->f_flags & O_ACCMODE) == O_RDONLY) - desiredAccess = GENERIC_READ; - else if ((file->f_flags & O_ACCMODE) == O_WRONLY) - desiredAccess = GENERIC_WRITE; - else if ((file->f_flags & O_ACCMODE) == O_RDWR) - desiredAccess = GENERIC_ALL; - if (oplockEnabled) - oplock = REQ_OPLOCK; - else - oplock = FALSE; + int rc = -EACCES; + int xid, oplock; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + struct cifsFileInfo *pCifsFile; + struct cifsInodeInfo *pCifsInode; + char *full_path = NULL; + int desiredAccess = 0x20197; + int disposition = FILE_OPEN; + __u16 netfid; + FILE_ALL_INFO * buf = NULL; + + if(inode == NULL) + return -EBADF; + if (file->private_data) { + pCifsFile = (struct cifsFileInfo *) file->private_data; + } else + return -EBADF; + + xid = GetXid(); + down(&pCifsFile->fh_sem); + if(pCifsFile->invalidHandle == FALSE) { + up(&pCifsFile->fh_sem); + FreeXid(xid); + return 0; + } + + + cifs_sb = CIFS_SB(inode->i_sb); + pTcon = cifs_sb->tcon; + + full_path = build_path_from_dentry(file->f_dentry); + + cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path)); + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + desiredAccess = GENERIC_READ; + else if ((file->f_flags & O_ACCMODE) == O_WRONLY) + desiredAccess = GENERIC_WRITE; + else if ((file->f_flags & O_ACCMODE) == O_RDWR) + desiredAccess = GENERIC_ALL; + + if (oplockEnabled) + oplock = REQ_OPLOCK; + else + oplock = FALSE; /* BB pass O_SYNC flag through on file attributes .. BB */ /* Also refresh inode by passing in file_info buf returned by SMBOpen and calling get_inode_info with returned buf (at least helps non-Unix server case */ - buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); - if(buf==0) { - if (full_path) - kfree(full_path); - FreeXid(xid); - return -ENOMEM; - } - rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, - CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls); - if (rc) { - cFYI(1, ("cifs_open returned 0x%x ", rc)); - cFYI(1, ("oplock: %d ", oplock)); - } else { - if (file->private_data) { - pCifsFile = (struct cifsFileInfo *) file->private_data; - - pCifsFile->netfid = netfid; - pCifsFile->invalidHandle = FALSE; - pCifsInode = CIFS_I(file->f_dentry->d_inode); - if(pCifsInode) { - if (pTcon->ses->capabilities & CAP_UNIX) - rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode, - full_path, inode->i_sb); - else - rc = cifs_get_inode_info(&file->f_dentry->d_inode, - full_path, buf, inode->i_sb); - - if(oplock == OPLOCK_EXCLUSIVE) { - pCifsInode->clientCanCacheAll = TRUE; - pCifsInode->clientCanCacheRead = TRUE; - cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode)); - } else if(oplock == OPLOCK_READ) { - pCifsInode->clientCanCacheRead = TRUE; - pCifsInode->clientCanCacheAll = FALSE; - } else { - pCifsInode->clientCanCacheRead = FALSE; - pCifsInode->clientCanCacheAll = FALSE; - } - } - } else - rc = -EBADF; - } - - if (buf) - kfree(buf); - if (full_path) - kfree(full_path); - FreeXid(xid); - return rc; -} - -/* Try to reopen files that were closed when session to server was lost */ -int reopen_files(struct cifsTconInfo * pTcon, struct nls_table * nlsinfo) -{ - int rc = 0; - struct cifsFileInfo *open_file = NULL; - struct file * file = NULL; - struct list_head invalid_file_list; - struct list_head * tmp; - struct list_head * tmp1; - - INIT_LIST_HEAD(&invalid_file_list); - -/* list all files open on tree connection and mark them invalid */ - write_lock(&GlobalSMBSeslock); - list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { - open_file = list_entry(tmp,struct cifsFileInfo, tlist); - if(open_file) { - open_file->invalidHandle = TRUE; - list_move(&open_file->tlist,&invalid_file_list); - } + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); + if(buf==0) { + up(&pCifsFile->fh_sem); + if (full_path) + kfree(full_path); + FreeXid(xid); + return -ENOMEM; } + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, + CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls); + if (rc) { + up(&pCifsFile->fh_sem); + cFYI(1, ("cifs_open returned 0x%x ", rc)); + cFYI(1, ("oplock: %d ", oplock)); + } else { + pCifsFile->netfid = netfid; + pCifsFile->invalidHandle = FALSE; + up(&pCifsFile->fh_sem); + pCifsInode = CIFS_I(inode); + if(pCifsInode) { + if (pTcon->ses->capabilities & CAP_UNIX) + rc = cifs_get_inode_info_unix(&inode, + full_path, inode->i_sb); + else + rc = cifs_get_inode_info(&inode, + full_path, buf, inode->i_sb); - /* reopen files */ - list_for_each_safe(tmp,tmp1, &invalid_file_list) { - /* BB need to fix above to check list end and skip entries we do not need to reopen */ - open_file = list_entry(tmp,struct cifsFileInfo, tlist); - if(open_file == NULL) { - break; - } else { - if((open_file->invalidHandle == FALSE) && - (open_file->closePend == FALSE)) { - list_move(&open_file->tlist,&pTcon->openFileList); - continue; - } - file = open_file->pfile; - if(file->f_dentry == 0) { - cFYI(1,("Null dentry for file %p",file)); + if(oplock == OPLOCK_EXCLUSIVE) { + pCifsInode->clientCanCacheAll = TRUE; + pCifsInode->clientCanCacheRead = TRUE; + cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode)); + } else if(oplock == OPLOCK_READ) { + pCifsInode->clientCanCacheRead = TRUE; + pCifsInode->clientCanCacheAll = FALSE; } else { - write_unlock(&GlobalSMBSeslock); - rc = cifs_reopen_file(file->f_dentry->d_inode,file); - write_lock(&GlobalSMBSeslock); - if(file->private_data == NULL) { - tmp = invalid_file_list.next; - tmp1 = tmp->next; - continue; - } - - list_move(&open_file->tlist,&pTcon->openFileList); - if(rc) { - cFYI(1,("reconnecting file %s failed with %d", - file->f_dentry->d_name.name,rc)); - } else { - cFYI(1,("reconnection of %s succeeded", - file->f_dentry->d_name.name)); - } + pCifsInode->clientCanCacheRead = FALSE; + pCifsInode->clientCanCacheAll = FALSE; } } } - write_unlock(&GlobalSMBSeslock); + + if (buf) + kfree(buf); + if (full_path) + kfree(full_path); + FreeXid(xid); return rc; } @@ -401,6 +353,7 @@ info on this inode, much less write behind and read ahead */ CIFS_I(inode)->clientCanCacheRead = FALSE; CIFS_I(inode)->clientCanCacheAll = FALSE; + invalidate_remote_inode(inode); } if((rc ==0) && CIFS_I(inode)->write_behind_rc) rc = CIFS_I(inode)->write_behind_rc; @@ -541,6 +494,7 @@ struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int xid, long_op; + struct cifsFileInfo * open_file; xid = GetXid(); @@ -555,20 +509,30 @@ FreeXid(xid); return -EBADF; } + open_file = (struct cifsFileInfo *) file->private_data; + if (*poffset > file->f_dentry->d_inode->i_size) - long_op = 2; /* writes past end of file can take a long time */ + long_op = 2; /* writes past end of file can take a long time */ else long_op = 1; for (total_written = 0; write_size > total_written; total_written += bytes_written) { - rc = CIFSSMBWrite(xid, pTcon, - ((struct cifsFileInfo *) file-> - private_data)->netfid, + rc = -EAGAIN; + while(rc == -EAGAIN) { + if ((open_file->invalidHandle) && (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode,file); + if(rc != 0) + break; + } + + rc = CIFSSMBWrite(xid, pTcon, + open_file->netfid, write_size - total_written, *poffset, &bytes_written, write_data + total_written, long_op); + } if (rc || (bytes_written == 0)) { if (total_written) break; @@ -580,7 +544,8 @@ *poffset += bytes_written; long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */ } - file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime = CURRENT_TIME; + file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime = + CURRENT_TIME; if (bytes_written > 0) { if (*poffset > file->f_dentry->d_inode->i_size) file->f_dentry->d_inode->i_size = *poffset; @@ -605,24 +570,18 @@ struct cifsFileInfo *open_file = NULL; struct list_head *tmp; struct list_head *tmp1; - int xid; - - xid = GetXid(); cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; /* figure out which file struct to use if (file->private_data == NULL) { - FreeXid(xid); return -EBADF; } */ if (!mapping) { - FreeXid(xid); return -EFAULT; } else if(!mapping->host) { - FreeXid(xid); return -EFAULT; } @@ -632,14 +591,12 @@ if((to > PAGE_CACHE_SIZE) || (from > to)) { kunmap(page); - FreeXid(xid); return -EIO; } /* racing with truncate? */ if(offset > mapping->host->i_size) { kunmap(page); - FreeXid(xid); return 0; /* don't care */ } @@ -683,7 +640,6 @@ } kunmap(page); - FreeXid(xid); return rc; } @@ -737,13 +693,28 @@ if (file->private_data == NULL) { rc = -EBADF; } else { - cifs_sb = CIFS_SB(inode->i_sb); open_file = (struct cifsFileInfo *)file->private_data; - rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, position, - open_file->netfid,open_file->pid,FALSE); + cifs_sb = CIFS_SB(inode->i_sb); + rc = -EAGAIN; + while(rc == -EAGAIN) { + if((open_file->invalidHandle) && + (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode,file); + if(rc != 0) + break; + } + if(!open_file->closePend) + rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, + position, open_file->netfid, + open_file->pid,FALSE); + else { + rc = -EBADF; + break; + } + } cFYI(1,(" SetEOF (commit write) rc = %d",rc)); } - } + } set_page_dirty(page); FreeXid(xid); @@ -837,6 +808,7 @@ struct cifsTconInfo *pTcon; int xid; char * current_offset; + struct cifsFileInfo * open_file; xid = GetXid(); cifs_sb = CIFS_SB(file->f_dentry->d_sb); @@ -846,15 +818,24 @@ FreeXid(xid); return -EBADF; } + open_file = (struct cifsFileInfo *)file->private_data; for (total_read = 0,current_offset=read_data; read_size > total_read; total_read += bytes_read,current_offset+=bytes_read) { current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize); - rc = CIFSSMBRead(xid, pTcon, - ((struct cifsFileInfo *) file-> - private_data)->netfid, + rc = -EAGAIN; + while(rc == -EAGAIN) { + if ((open_file->invalidHandle) && (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode,file); + if(rc != 0) + break; + } + + rc = CIFSSMBRead(xid, pTcon, + open_file->netfid, current_read_size, *poffset, &bytes_read, ¤t_offset); + } if (rc || (bytes_read == 0)) { if (total_read) { break; @@ -862,8 +843,9 @@ FreeXid(xid); return rc; } - } else + } else { *poffset += bytes_read; + } } FreeXid(xid); @@ -949,13 +931,14 @@ char * smb_read_data = 0; struct smb_com_read_rsp * pSMBr; struct pagevec lru_pvec; + struct cifsFileInfo * open_file; xid = GetXid(); if (file->private_data == NULL) { FreeXid(xid); return -EBADF; } - + open_file = (struct cifsFileInfo *)file->private_data; cifs_sb = CIFS_SB(file->f_dentry->d_sb); pTcon = cifs_sb->tcon; @@ -979,16 +962,23 @@ read_size = (num_pages - i) * PAGE_CACHE_SIZE; /* Read size needs to be in multiples of one page */ read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK); - rc = CIFSSMBRead(xid, pTcon, - ((struct cifsFileInfo *) file-> - private_data)->netfid, - read_size, offset, - &bytes_read, &smb_read_data); + rc = -EAGAIN; + while(rc == -EAGAIN) { + if ((open_file->invalidHandle) && (!open_file->closePend)) { + rc = cifs_reopen_file(file->f_dentry->d_inode,file); + if(rc != 0) + break; + } + + rc = CIFSSMBRead(xid, pTcon, + open_file->netfid, + read_size, offset, + &bytes_read, &smb_read_data); + } if ((rc < 0) || (smb_read_data == NULL)) { cFYI(1,("Read error in readpages: %d",rc)); - /* clean up remaing pages off list */ - + /* clean up remaing pages off list */ spin_lock(&mapping->page_lock); while (!list_empty(page_list) && (i < num_pages)) { page = list_entry(page_list->prev, struct page, list); @@ -1226,7 +1216,7 @@ } } -void +static void construct_dentry(struct qstr *qstring, struct file *file, struct inode **ptmp_inode, struct dentry **pnew_dentry) { @@ -1262,13 +1252,36 @@ *pnew_dentry = tmp_dentry; } -void +static void reset_resume_key(struct file * dir_file, + unsigned char * filename, + unsigned int len) { + struct cifsFileInfo *cifsFile; + + cifsFile = (struct cifsFileInfo *)dir_file->private_data; + if(cifsFile == NULL) + return; + if(cifsFile->search_resume_name) { + kfree(cifsFile->search_resume_name); + } + + cifsFile->resume_name_length = len; + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + memcpy(cifsFile->search_resume_name, filename, + cifsFile->resume_name_length); + cFYI(1,("Reset resume key to: %s",filename)); + return; +} + + + +static int cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData, struct file *file, filldir_t filldir, void *direntry) { struct inode *tmp_inode; struct dentry *tmp_dentry; - int object_type; + int object_type,rc; pqstring->name = pfindData->FileName; pqstring->len = pfindData->FileNameLength; @@ -1276,19 +1289,26 @@ construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); fill_in_inode(tmp_inode, pfindData, &object_type); - filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, + rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, tmp_inode->i_ino, object_type); + if(rc) { + /* due to readdir error we need to recalculate resume + key so next readdir will restart on right entry */ + reset_resume_key(file, pfindData->FileName, pqstring->len); + cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName)); + } dput(tmp_dentry); + return rc; } -void +static int cifs_filldir_unix(struct qstr *pqstring, FILE_UNIX_INFO * pUnixFindData, struct file *file, filldir_t filldir, void *direntry) { struct inode *tmp_inode; struct dentry *tmp_dentry; - int object_type; + int object_type, rc; pqstring->name = pUnixFindData->FileName; pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF); @@ -1296,9 +1316,16 @@ construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type); - filldir(direntry, pUnixFindData->FileName, pqstring->len, + rc = filldir(direntry, pUnixFindData->FileName, pqstring->len, file->f_pos, tmp_inode->i_ino, object_type); + if(rc) { + /* due to readdir error we need to recalculate resume + key so next readdir will restart on right entry */ + reset_resume_key(file, pUnixFindData->FileName,pqstring->len); + cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName)); + } dput(tmp_dentry); + return rc; } int @@ -1393,6 +1420,7 @@ (struct cifsFileInfo *) file->private_data; cifsFile->netfid = searchHandle; cifsFile->invalidHandle = FALSE; + init_MUTEX(&cifsFile->fh_sem); } else { rc = -ENOMEM; break; @@ -1477,10 +1505,16 @@ FileName[0] != '.') || (pfindData-> FileName[1] != '.'))) { - cifs_filldir(&qstring, + if(cifs_filldir(&qstring, pfindData, file, filldir, - direntry); + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findParms.EndofSearch = 0; + break; + } file->f_pos++; } } else { /* UnixSearch */ @@ -1507,11 +1541,17 @@ FileName[0] != '.') || (pfindDataUnix-> FileName[1] != '.'))) { - cifs_filldir_unix(&qstring, + if(cifs_filldir_unix(&qstring, pfindDataUnix, file, filldir, - direntry); + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findParms.EndofSearch = 0; + break; + } file->f_pos++; } } @@ -1579,6 +1619,11 @@ rc = -ENOMEM; break; } + /* Free the memory allocated by previous findfirst + or findnext call - we can not reuse the memory since + the resume name may not be same string length */ + if(cifsFile->search_resume_name) + kfree(cifsFile->search_resume_name); cifsFile->search_resume_name = kmalloc(cifsFile->resume_name_length, GFP_KERNEL); cFYI(1,("Last file: %s with name %d bytes long", @@ -1609,6 +1654,11 @@ rc = -ENOMEM; break; } + /* Free the memory allocated by previous findfirst + or findnext call - we can not reuse the memory since + the resume name may not be same string length */ + if(cifsFile->search_resume_name) + kfree(cifsFile->search_resume_name); cifsFile->search_resume_name = kmalloc(cifsFile->resume_name_length, GFP_KERNEL); cFYI(1,("fnext last file: %s with name %d bytes long", @@ -1640,11 +1690,17 @@ || (pfindData->FileName[0] != '.') || (pfindData->FileName[1] != '.'))) { - cifs_filldir + if(cifs_filldir (&qstring, pfindData, file, filldir, - direntry); + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findNextParms.EndofSearch = 0; + break; + } file->f_pos++; } } else { /* UnixSearch */ @@ -1674,11 +1730,17 @@ || (pfindDataUnix-> FileName[1] != '.'))) { - cifs_filldir_unix + if(cifs_filldir_unix (&qstring, pfindDataUnix, file, filldir, - direntry); + direntry)) { + /* do not end search if + kernel not ready to take + remaining entries yet */ + findNextParms.EndofSearch = 0; + break; + } file->f_pos++; } } diff -Nau bk/linux-2.5/fs/cifs/inode.c /home/stevef/bk/linux-2.5cifs/fs/cifs/inode.c --- bk/linux-2.5/fs/cifs/inode.c 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/inode.c 2003-12-08 11:51:31.000000000 -0600 @@ -426,6 +426,7 @@ rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls); if (rc) { cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); + d_drop(direntry); } else { inode->i_nlink++; if (pTcon->ses->capabilities & CAP_UNIX) @@ -627,12 +628,14 @@ cifs_truncate_file(struct inode *inode) { /* BB remove - may not need this function after all BB */ int xid; - int rc = 0; + int rc = -EIO; + int found = FALSE; struct cifsFileInfo *open_file = NULL; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; struct cifsInodeInfo *cifsInode; struct dentry *dirent; + struct list_head * tmp; char *full_path = NULL; xid = GetXid(); @@ -640,6 +643,41 @@ cifs_sb = CIFS_SB(inode->i_sb); pTcon = cifs_sb->tcon; + /* 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. + This keeps our caching token (oplock) and avoids + timeouts when the local oplock break takes longer to flush + writebehind data than the SMB timeout for the SetPathInfo + request would allow */ + read_lock(&GlobalSMBSeslock); + cifsInode = CIFS_I(inode); + 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->invalidHandle) && + ((open_file->pfile->f_flags & O_RDWR) || + (open_file->pfile->f_flags & O_WRONLY))) { + read_unlock(&GlobalSMBSeslock); + found = TRUE; + rc = CIFSSMBSetFileSize(xid, pTcon, inode->i_size, + open_file->netfid,open_file->pid,FALSE); + if(rc == 0) { + FreeXid(xid); + return; + } + /* Do not need reopen and retry on EAGAIN since we will + retry by pathname below */ + if(rc == -EAGAIN) + rc = -EHOSTDOWN; + + break; /* now that we found one valid file handle no + sense continuing to loop trying others */ + } + } + if(found == FALSE) + read_unlock(&GlobalSMBSeslock); + if (list_empty(&inode->i_dentry)) { cERROR(1, ("Can not get pathname from empty dentry in inode 0x%p ", @@ -647,24 +685,13 @@ FreeXid(xid); return; } + dirent = list_entry(inode->i_dentry.next, struct dentry, d_alias); if (dirent) { full_path = build_path_from_dentry(dirent); rc = CIFSSMBSetEOF(xid, pTcon, full_path, inode->i_size,FALSE, cifs_sb->local_nls); cFYI(1,(" SetEOF (truncate) rc = %d",rc)); - if(rc == -ETXTBSY) { - cifsInode = CIFS_I(inode); - if(!list_empty(&(cifsInode->openFileList))) { - open_file = list_entry(cifsInode->openFileList.next, - struct cifsFileInfo, flist); - /* We could check if file is open for writing first */ - rc = CIFSSMBSetFileSize(xid, pTcon, inode->i_size, - open_file->netfid,open_file->pid,FALSE); - } else { - cFYI(1,(" No open files to get file handle from")); - } - } if (!rc) CIFSSMBSetEOF(xid,pTcon,full_path,inode->i_size,TRUE,cifs_sb->local_nls); /* allocation size setting seems optional so ignore return code */ @@ -705,6 +732,7 @@ 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; @@ -712,6 +740,7 @@ __u64 uid = 0xFFFFFFFFFFFFFFFFULL; __u64 gid = 0xFFFFFFFFFFFFFFFFULL; struct cifsInodeInfo *cifsInode; + struct list_head * tmp; xid = GetXid(); @@ -729,28 +758,57 @@ cFYI(1, (" Changing attributes 0x%x", attrs->ia_valid)); if (attrs->ia_valid & ATTR_SIZE) { - rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE, - cifs_sb->local_nls); - cFYI(1,(" SetEOF (setattrs) rc = %d",rc)); - - if(rc == -ETXTBSY) { - if(!list_empty(&(cifsInode->openFileList))) { - open_file = list_entry(cifsInode->openFileList.next, - struct cifsFileInfo, flist); - /* We could check if file is open for writing first */ - rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, - open_file->netfid,open_file->pid,FALSE); - } else { - cFYI(1,(" No open files to get file handle from")); + 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. + This keeps our caching token (oplock) and avoids + timeouts 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 */ + + break; /* now that we found one valid file handle no + sense continuing to loop trying others */ + } } } + 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 it was found or + because there was an error setting it by handle */ + rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE, + cifs_sb->local_nls); + cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc)); + } + /* For Allocation Size - do not need to call the following it did not hurt if it fails but why bother */ /* CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/ + if (rc == 0) { rc = vmtruncate(direntry->d_inode, attrs->ia_size); cifs_trunc_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size); - /* cFYI(1,("truncate_page to 0x%lx \n",direntry->d_inode->i_size)); */ } } @@ -816,6 +874,8 @@ /* 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 */ rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, cifs_sb->local_nls); } diff -Nau bk/linux-2.5/fs/cifs/md4.c /home/stevef/bk/linux-2.5cifs/fs/cifs/md4.c --- bk/linux-2.5/fs/cifs/md4.c 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/md4.c 2003-12-08 11:51:31.000000000 -0600 @@ -3,7 +3,7 @@ Version 1.9. a implementation of MD4 designed for use in the SMB authentication protocol Copyright (C) Andrew Tridgell 1997-1998. - Modified by Steve French (sfrench@us.ibm.com) 2002 + Modified by Steve French (sfrench@us.ibm.com) 2002-2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,13 +21,7 @@ */ #include #include - -/* NOTE: This code makes no attempt to be fast! - - It assumes that a int is at least 32 bits long -*/ - -static __u32 A, B, C, D; +/* NOTE: This code makes no attempt to be fast! */ static __u32 F(__u32 X, __u32 Y, __u32 Z) @@ -54,25 +48,26 @@ return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); } -#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s) -#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (__u32)0x5A827999,s) -#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (__u32)0x6ED9EBA1,s) +#define ROUND1(a,b,c,d,k,s) (*a) = lshift((*a) + F(*b,*c,*d) + X[k], s) +#define ROUND2(a,b,c,d,k,s) (*a) = lshift((*a) + G(*b,*c,*d) + X[k] + (__u32)0x5A827999,s) +#define ROUND3(a,b,c,d,k,s) (*a) = lshift((*a) + H(*b,*c,*d) + X[k] + (__u32)0x6ED9EBA1,s) /* this applies md4 to 64 byte chunks */ static void -mdfour64(__u32 * M) +mdfour64(__u32 * M, __u32 * A, __u32 *B, __u32 * C, __u32 *D) { int j; __u32 AA, BB, CC, DD; __u32 X[16]; + for (j = 0; j < 16; j++) X[j] = M[j]; - AA = A; - BB = B; - CC = C; - DD = D; + AA = *A; + BB = *B; + CC = *C; + DD = *D; ROUND1(A, B, C, D, 0, 3); ROUND1(D, A, B, C, 1, 7); @@ -125,15 +120,15 @@ ROUND3(C, D, A, B, 7, 11); ROUND3(B, C, D, A, 15, 15); - A += AA; - B += BB; - C += CC; - D += DD; - - A &= 0xFFFFFFFF; - B &= 0xFFFFFFFF; - C &= 0xFFFFFFFF; - D &= 0xFFFFFFFF; + *A += AA; + *B += BB; + *C += CC; + *D += DD; + + *A &= 0xFFFFFFFF; + *B &= 0xFFFFFFFF; + *C &= 0xFFFFFFFF; + *D &= 0xFFFFFFFF; for (j = 0; j < 16; j++) X[j] = 0; @@ -166,15 +161,14 @@ __u32 M[16]; __u32 b = n * 8; int i; - - A = 0x67452301; - B = 0xefcdab89; - C = 0x98badcfe; - D = 0x10325476; + __u32 A = 0x67452301; + __u32 B = 0xefcdab89; + __u32 C = 0x98badcfe; + __u32 D = 0x10325476; while (n > 64) { copy64(M, in); - mdfour64(M); + mdfour64(M,&A,&B, &C, &D); in += 64; n -= 64; } @@ -187,13 +181,13 @@ if (n <= 55) { copy4(buf + 56, b); copy64(M, buf); - mdfour64(M); + mdfour64(M, &A, &B, &C, &D); } else { copy4(buf + 120, b); copy64(M, buf); - mdfour64(M); + mdfour64(M, &A, &B, &C, &D); copy64(M, buf + 64); - mdfour64(M); + mdfour64(M, &A, &B, &C, &D); } for (i = 0; i < 128; i++) diff -Nau bk/linux-2.5/fs/cifs/misc.c /home/stevef/bk/linux-2.5cifs/fs/cifs/misc.c --- bk/linux-2.5/fs/cifs/misc.c 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/misc.c 2003-11-03 18:36:05.000000000 -0600 @@ -25,6 +25,8 @@ #include "cifsglob.h" #include "cifsproto.h" #include "cifs_debug.h" +#include "smberr.h" +#include "nterr.h" extern kmem_cache_t *cifs_req_cachep; extern struct task_struct * oplockThread; @@ -369,8 +371,22 @@ cFYI(1,("Checking for oplock break")); if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX) return FALSE; - if(pSMB->hdr.Flags & SMBFLG_RESPONSE) - return FALSE; /* server sends us "request" here */ + if(pSMB->hdr.Flags & SMBFLG_RESPONSE) { + /* no sense logging error on invalid handle on oplock + break - harmless race between close request and oplock + break response is expected from time to time writing out + large dirty files cached on the client */ + if ((NT_STATUS_INVALID_HANDLE) == + le32_to_cpu(pSMB->hdr.Status.CifsError)) { + cFYI(1,("invalid handle on oplock break")); + return TRUE; + } else if (ERRbadfid == + le16_to_cpu(pSMB->hdr.Status.DosError.Error)) { + return TRUE; + } else { + return FALSE; /* on valid oplock brk we get "request" */ + } + } if(pSMB->hdr.WordCount != 8) return FALSE; diff -Nau bk/linux-2.5/fs/cifs/smbencrypt.c /home/stevef/bk/linux-2.5cifs/fs/cifs/smbencrypt.c --- bk/linux-2.5/fs/cifs/smbencrypt.c 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/smbencrypt.c 2003-12-08 11:51:31.000000000 -0600 @@ -23,8 +23,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -extern int DEBUGLEVEL; - #include #include #include @@ -96,12 +94,6 @@ SMBOWFencrypt(p21, c8, p24); -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBencrypt: lm#, challenge, response\n")); - dump_data(100, (char *) p21, 16); - dump_data(100, (char *) c8, 8); - dump_data(100, (char *) p24, 24); -#endif memset(p14,0,15); memset(p21,0,21); } @@ -179,12 +171,6 @@ memset(nt_p16, '\0', 16); E_md4hash(passwd, nt_p16); -#ifdef DEBUG_PASSWORD - DEBUG(100, ("nt_lm_owf_gen: pwd, nt#\n")); - dump_data(120, passwd, strlen(passwd)); - dump_data(100, (char *) nt_p16, 16); -#endif - /* Mangle the passwords into Lanman format */ passwd[14] = '\0'; /* strupper(passwd); */ @@ -194,11 +180,6 @@ memset(p16, '\0', 16); E_P16((unsigned char *) passwd, (unsigned char *) p16); -#ifdef DEBUG_PASSWORD - DEBUG(100, ("nt_lm_owf_gen: pwd, lm#\n")); - dump_data(120, passwd, strlen(passwd)); - dump_data(100, (char *) p16, 16); -#endif /* clear out local copy of user's password (just being paranoid). */ memset(passwd, '\0', sizeof (passwd)); } @@ -235,13 +216,6 @@ hmac_md5_update((const unsigned char *) dom_u, domain_l * 2, &ctx); hmac_md5_final(kr_buf, &ctx); -#ifdef DEBUG_PASSWORD - DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n")); - dump_data(100, user_u, user_l * 2); - dump_data(100, dom_u, domain_l * 2); - dump_data(100, owf, 16); - dump_data(100, kr_buf, 16); -#endif kfree(user_u); } @@ -270,12 +244,6 @@ memset(p21 + 8, 0xbd, 8); E_P24(p21, ntlmchalresp, p24); -#ifdef DEBUG_PASSWORD - DEBUG(100, ("NTLMSSPOWFencrypt: p21, c8, p24\n")); - dump_data(100, (char *) p21, 21); - dump_data(100, (char *) ntlmchalresp, 8); - dump_data(100, (char *) p24, 24); -#endif } /* Does the NT MD4 hash then des encryption. */ @@ -289,13 +257,6 @@ E_md4hash(passwd, p21); SMBOWFencrypt(p21, c8, p24); - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBNTencrypt: nt#, challenge, response\n")); - dump_data(100, (char *) p21, 16); - dump_data(100, (char *) c8, 8); - dump_data(100, (char *) p24, 24); -#endif } /* Does the md5 encryption from the NT hash for NTLMv2. */ @@ -310,37 +271,6 @@ hmac_md5_update(srv_chal->data, srv_chal->length, &ctx); hmac_md5_update(cli_chal->data, cli_chal->length, &ctx); hmac_md5_final(resp_buf, &ctx); - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n")); - dump_data(100, srv_chal->data, srv_chal->length); - dump_data(100, cli_chal->data, cli_chal->length); - dump_data(100, resp_buf, 16); -#endif -} - -static struct data_blob LMv2_generate_response(const unsigned char ntlm_v2_hash[16], - const struct data_blob * server_chal) -{ - unsigned char lmv2_response[16]; - struct data_blob lmv2_client_data/* = data_blob(NULL, 8)*/; /* BB Fix BB */ - struct data_blob final_response /* = data_blob(NULL, 24)*/; /* BB Fix BB */ - - /* LMv2 */ - /* client-supplied random data */ - get_random_bytes(lmv2_client_data.data, lmv2_client_data.length); - /* Given that data, and the challenge from the server, generate a response */ - SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &lmv2_client_data, lmv2_response); - memcpy(final_response.data, lmv2_response, sizeof(lmv2_response)); - - /* after the first 16 bytes is the random data we generated above, - so the server can verify us with it */ - memcpy(final_response.data+sizeof(lmv2_response), - lmv2_client_data.data, lmv2_client_data.length); - -/* data_blob_free(&lmv2_client_data); */ /* BB fix BB */ - - return final_response; } void @@ -352,11 +282,6 @@ hmac_md5_init_limK_to_64(kr, 16, &ctx); hmac_md5_update(nt_resp, 16, &ctx); hmac_md5_final((unsigned char *) sess_key, &ctx); - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBsesskeygen_ntv2:\n")); - dump_data(100, sess_key, 16); -#endif } void @@ -364,11 +289,6 @@ const unsigned char *nt_resp, __u8 sess_key[16]) { mdfour((unsigned char *) sess_key, (unsigned char *) kr, 16); - -#ifdef DEBUG_PASSWORD - DEBUG(100, ("SMBsesskeygen_ntv1:\n")); - dump_data(100, sess_key, 16); -#endif } /*********************************************************** @@ -391,39 +311,3 @@ return TRUE; } -int SMBNTLMv2encrypt(const char *user, const char *domain, const char *password, - const struct data_blob *server_chal, - const struct data_blob *names_blob, - struct data_blob *lm_response, struct data_blob *nt_response, - struct data_blob *nt_session_key,struct nls_table * nls_codepage) -{ - unsigned char nt_hash[16]; - unsigned char ntlm_v2_hash[16]; - E_md4hash(password, nt_hash); - - /* We don't use the NT# directly. Instead we use it mashed up with - the username and domain. - This prevents username swapping during the auth exchange - */ - ntv2_owf_gen(nt_hash, user, domain, ntlm_v2_hash,nls_codepage); - - if (nt_response) { -/* *nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal, - names_blob); */ /* BB fix BB */ - if (nt_session_key) { -/* *nt_session_key = data_blob(NULL, 16); */ /* BB fix BB */ - - /* The NTLMv2 calculations also provide a session key, for signing etc later */ - /* use only the first 16 bytes of nt_response for session key */ - SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, nt_session_key->data); - } - } - - /* LMv2 */ - - if (lm_response) { - *lm_response = LMv2_generate_response(ntlm_v2_hash, server_chal); - } - - return TRUE; -} diff -Nau bk/linux-2.5/fs/cifs/transport.c /home/stevef/bk/linux-2.5cifs/fs/cifs/transport.c --- bk/linux-2.5/fs/cifs/transport.c 2003-12-08 11:53:27.000000000 -0600 +++ /home/stevef/bk/linux-2.5cifs/fs/cifs/transport.c 2003-12-08 11:51:31.000000000 -0600 @@ -37,7 +37,6 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) { struct mid_q_entry *temp; - int timeout = 10 * HZ; if (ses == NULL) { cERROR(1, ("Null session passed in to AllocMidQEntry ")); @@ -63,25 +62,11 @@ temp->tsk = current; } - while ((ses->server->tcpStatus != CifsGood) && (timeout > 0)){ - /* Give the tcp thread up to 10 seconds to reconnect */ - /* Should we wake up tcp thread first? BB */ - timeout = wait_event_interruptible_timeout(ses->server->response_q, - (ses->server->tcpStatus == CifsGood), timeout); - } - - if (ses->server->tcpStatus == CifsGood) { - spin_lock(&GlobalMid_Lock); - list_add_tail(&temp->qhead, &ses->server->pending_mid_q); - atomic_inc(&midCount); - temp->midState = MID_REQUEST_ALLOCATED; - spin_unlock(&GlobalMid_Lock); - } else { - cERROR(1,("Need to reconnect after session died to server")); - if (temp) - kmem_cache_free(cifs_mid_cachep, temp); - return NULL; - } + spin_lock(&GlobalMid_Lock); + list_add_tail(&temp->qhead, &ses->server->pending_mid_q); + atomic_inc(&midCount); + temp->midState = MID_REQUEST_ALLOCATED; + spin_unlock(&GlobalMid_Lock); return temp; } @@ -190,10 +175,35 @@ long timeout; struct mid_q_entry *midQ; + if ((ses == NULL) || (ses->server == NULL)) { + cERROR(1,("Null tcp session or smb session: %p",ses)); + return -EIO; + } + + if (ses->server->tcpStatus == CifsExiting) { + return -ENOENT; + } else if (ses->server->tcpStatus == CifsNeedReconnect) { + cFYI(1,("tcp session dead - return to caller to retry")); + return -EAGAIN; + } else if (ses->status != CifsGood) { + /* check if SMB session is bad because we are setting it up */ + if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && + (in_buf->Command != SMB_COM_NEGOTIATE)) { + return -EAGAIN; + } /* else ok - we are setting up session */ + } + /* make sure that we sign in the same order that we send on this socket + and avoid races inside tcp sendmsg code that could cause corruption + of smb data */ + down(&ses->server->tcpSem); midQ = AllocMidQEntry(in_buf, ses); - if (midQ == NULL) + if (midQ == NULL) { + up(&ses->server->tcpSem); return -EIO; + } + if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) { + up(&ses->server->tcpSem); cERROR(1, ("Illegal length, greater than maximum frame, %d ", in_buf->smb_buf_length)); @@ -201,15 +211,15 @@ return -EIO; } - if (in_buf->smb_buf_length > 12) - in_buf->Flags2 = cpu_to_le16(in_buf->Flags2); + if (in_buf->smb_buf_length > 12) + in_buf->Flags2 = cpu_to_le16(in_buf->Flags2); - rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); + rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, (struct sockaddr *) &(ses->server->sockAddr)); - + up(&ses->server->tcpSem); if (long_op == -1) goto cifs_no_response_exit; if (long_op > 1) /* writes past end of file can take looooong time */ @@ -227,26 +237,35 @@ midState & MID_RESPONSE_RECEIVED, timeout); if (signal_pending(current)) { - cERROR(1, ("CIFS: caught signal")); + cFYI(1, ("CIFS: caught signal")); DeleteMidQEntry(midQ); return -EINTR; - } else { - if (midQ->resp_buf) + } else { /* BB spinlock protect this against races with demux thread */ + spin_lock(&GlobalMid_Lock); + if (midQ->resp_buf) { + spin_unlock(&GlobalMid_Lock); receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); - else { + } else { cFYI(1,("No response buffer")); + if(midQ->midState == MID_REQUEST_SUBMITTED) { + ses->server->tcpStatus = CifsNeedReconnect; + midQ->midState = MID_RETRY_NEEDED; + } + + if(midQ->midState == MID_RETRY_NEEDED) { + rc = -EAGAIN; + cFYI(1,("marking request for retry")); + } else { + rc = -EIO; + } + spin_unlock(&GlobalMid_Lock); DeleteMidQEntry(midQ); - ses->server->tcpStatus = CifsNeedReconnect; - return -EIO; + return rc; } } - if (timeout == 0) { - cFYI(1, - ("Timeout on receive. Assume response SMB is invalid.")); - rc = -ETIMEDOUT; - } else if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) { + if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) { cERROR(1, ("Frame too large received. Length: %d Xid: %d", receive_len, xid));