bk://cifs.bkbits.net/linux-2.5cifs stevef@stevef95.austin.ibm.com|ChangeSet|20040420173150|14568 stevef # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/04/20 12:31:50-05:00 stevef@stevef95.austin.ibm.com # Do not cache inode metadata when cache time set to 0 (fix hardlink count caching) # # fs/cifs/inode.c # 2004/04/20 12:31:36-05:00 stevef@stevef95.austin.ibm.com +4 -2 # Do not cache inode metadata when cache time set to 0 (fix hardlink count caching) # # fs/cifs/CHANGES # 2004/04/20 12:31:36-05:00 stevef@stevef95.austin.ibm.com +3 -1 # Update change log for cifs version 1.09 # # ChangeSet # 2004/04/19 19:23:58-07:00 akpm@bix.(none) # Merge bk://cifs.bkbits.net/linux-2.5cifs # into bix.(none):/usr/src/bk-cifs # # fs/cifs/cifsfs.c # 2004/04/19 19:23:56-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/19 14:31:26-05:00 stevef@stevef95.austin.ibm.com # Add in cifs fcntl handling to fix remote dnotify problem # # fs/cifs/fcntl.c # 2004/04/19 14:31:18-05:00 stevef@stevef95.austin.ibm.com +97 -0 # # fs/cifs/fcntl.c # 2004/04/19 14:31:18-05:00 stevef@stevef95.austin.ibm.com +0 -0 # BitKeeper file /usr/src/bk/linux-2.5cifs/fs/cifs/fcntl.c # # fs/cifs/cifsfs.h # 2004/04/19 14:31:18-05:00 stevef@stevef95.austin.ibm.com +1 -0 # Add in cifs fcntl handling to fix remote dnotify problem # # fs/cifs/cifsfs.c # 2004/04/19 14:31:18-05:00 stevef@stevef95.austin.ibm.com +7 -1 # Add in cifs fcntl handling to fix remote dnotify problem # # fs/cifs/Makefile # 2004/04/19 14:31:18-05:00 stevef@stevef95.austin.ibm.com +1 -1 # Add in cifs fcntl handling to fix remote dnotify problem # # fs/cifs/CHANGES # 2004/04/19 14:31:18-05:00 stevef@stevef95.austin.ibm.com +5 -0 # Update change log for cifs version 1.09 # # ChangeSet # 2004/04/19 12:18:17-05:00 stevef@stevef95.austin.ibm.com # Remove "badness in remove_proc_entry" warning logged on module unload of cifs # # fs/cifs/cifs_debug.c # 2004/04/19 12:17:17-05:00 stevef@stevef95.austin.ibm.com +1 -1 # Remove "badness in remove_proc_entry" warning logged on module unload of cifs # # ChangeSet # 2004/04/16 20:19:53-07:00 akpm@bix.(none) # Merge bk://cifs.bkbits.net/linux-2.5cifs # into bix.(none):/usr/src/bk-cifs # # fs/cifs/cifsfs.c # 2004/04/16 20:19:51-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/16 20:18:59-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-cifs # # fs/cifs/cifsfs.c # 2004/04/16 20:18:56-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/16 17:32:36-07:00 cifs.adm@hostme.bitkeeper.com # Merge bk://linux.bkbits.net/linux-2.5 # into hostme.bitkeeper.com:/repos/c/cifs/linux-2.5cifs # # fs/cifs/cifsfs.c # 2004/04/16 17:32:30-07:00 cifs.adm@hostme.bitkeeper.com +0 -0 # Auto merged # # ChangeSet # 2004/04/16 11:20:24-05:00 stevef@stevef95.austin.ibm.com # Remove 64 bit compiler warning # # fs/cifs/cifsfs.c # 2004/04/16 11:20:02-05:00 stevef@stevef95.austin.ibm.com +2 -2 # Remove 64 bit compiler warning # # ChangeSet # 2004/04/15 22:17:31-05:00 stevef@smfhome.smfdom # check permission locally for servers that do not support the CIFS Unix Extensions (allowing file_mode and dir_mode to augment the # server permission check, by doing local vfs_permission check) # # fs/cifs/connect.c # 2004/04/15 22:14:00-05:00 stevef@smfhome.smfdom +3 -1 # Fix multiple mount problem (mount to same server) temporarily introduced when compiler warning removed from cifs_mount # # fs/cifs/cifsfs.c # 2004/04/15 22:14:00-05:00 stevef@smfhome.smfdom +15 -2 # check permission locally for servers that do not support the CIFS Unix Extensions (allowing file_mode and dir_mode to augment the # server permission check, by doing local vfs_permission check) # # fs/cifs/CHANGES # 2004/04/15 22:14:00-05:00 stevef@smfhome.smfdom +7 -0 # update change log for cifs version 1.08 # # ChangeSet # 2004/04/15 17:51:05-05:00 stevef@stevef95.austin.ibm.com # Fix major page leak in read code caused by extra page_cache_get call # # fs/cifs/netmisc.c # 2004/04/15 17:50:57-05:00 stevef@stevef95.austin.ibm.com +11 -5 # remove ipv6 compiler warning # # fs/cifs/file.c # 2004/04/15 17:50:57-05:00 stevef@stevef95.austin.ibm.com +7 -9 # Fix major page leak in read code caused by extra page_cache_get call # # fs/cifs/connect.c # 2004/04/15 17:50:57-05:00 stevef@stevef95.austin.ibm.com +18 -2 # remove ipv6 compiler warning # # fs/cifs/CHANGES # 2004/04/15 17:50:57-05:00 stevef@stevef95.austin.ibm.com +3 -1 # Update change log for cifs 1.07a # # ChangeSet # 2004/04/14 16:45:54-05:00 stevef@stevef95.austin.ibm.com # free cifs read buffer on retry # # fs/cifs/file.c # 2004/04/14 16:45:39-05:00 stevef@stevef95.austin.ibm.com +6 -0 # free buffer on retry # # ChangeSet # 2004/04/14 16:19:59-05:00 stevef@stevef95.austin.ibm.com # Fix misc. minor memory leaks in error paths # # fs/cifs/link.c # 2004/04/14 16:19:51-05:00 stevef@stevef95.austin.ibm.com +7 -2 # Fix misc. minor memory leaks in error paths # # fs/cifs/inode.c # 2004/04/14 16:19:51-05:00 stevef@stevef95.austin.ibm.com +11 -11 # white space cleanup # # fs/cifs/file.c # 2004/04/14 16:19:50-05:00 stevef@stevef95.austin.ibm.com +10 -10 # Fix misc. minor memory leaks in error paths # # fs/cifs/connect.c # 2004/04/14 16:19:50-05:00 stevef@stevef95.austin.ibm.com +45 -4 # Fix misc. minor memory leaks in error paths # # fs/cifs/cifssmb.c # 2004/04/14 16:19:50-05:00 stevef@stevef95.austin.ibm.com +27 -27 # white space cleanup # # fs/cifs/cifsfs.c # 2004/04/14 16:19:50-05:00 stevef@stevef95.austin.ibm.com +4 -3 # Fix misc. minor memory leaks in error paths # # fs/cifs/CHANGES # 2004/04/14 16:19:50-05:00 stevef@stevef95.austin.ibm.com +4 -0 # Fix misc. minor memory leaks in error paths # # ChangeSet # 2004/04/13 16:58:22-05:00 stevef@stevef95.austin.ibm.com # fix merge problem with 2.6.5 (rename of page struct field list to lru) # # fs/cifs/file.c # 2004/04/13 16:58:14-05:00 stevef@stevef95.austin.ibm.com +2 -2 # fix merge problem with 2.6.5 (rename of page struct field list to lru) # # ChangeSet # 2004/04/13 14:31:41-05:00 stevef@stevef95.austin.ibm.com # Resolve merge conflict due to list to lru field renaming in page struct # # fs/cifs/file.c # 2004/04/13 14:31:34-05:00 stevef@stevef95.austin.ibm.com +10 -7 # Resolve merge conflict due to list to lru field renaming in page struct # # ChangeSet # 2004/04/06 20:30:33-05:00 stevef@steveft21.ltcsamba # Fix 20 second hang on some deletes of reopened file due to semaphore conflict with vfs_delete on i_sem # # fs/cifs/file.c # 2004/04/06 20:30:14-05:00 stevef@steveft21.ltcsamba +0 -8 # cleanup unused disabled error logging # # fs/cifs/cifsfs.c # 2004/04/06 20:30:14-05:00 stevef@steveft21.ltcsamba +7 -2 # Fix 20 second hang on some deletes of reopened file due to semaphore conflict with vfs_delete on i_sem # # fs/cifs/cifsencrypt.c # 2004/04/06 20:30:13-05:00 stevef@steveft21.ltcsamba +13 -14 # fix whitespace # # fs/cifs/CHANGES # 2004/04/06 20:30:13-05:00 stevef@steveft21.ltcsamba +3 -1 # update cifs vfs changelog for 1.06 version # # ChangeSet # 2004/04/05 21:34:11-05:00 stevef@steveft21.ltcsamba # Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated # with server. This allows files that differ only in case and # improves performance of file creation and file open to such servers # # fs/cifs/cifssmb.c # 2004/04/05 21:23:08-05:00 stevef@steveft21.ltcsamba +8 -2 # Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated # with server. This allows files that differ only in case and # improves performance of file creation and file open to such servers # # fs/cifs/CHANGES # 2004/04/05 21:23:07-05:00 stevef@steveft21.ltcsamba +7 -0 # Update CIFS VFS changelog for 1.0.6 # # ChangeSet # 2004/04/02 16:54:19-06:00 stevef@stevef95.austin.ibm.com # Invalidate readahead data properly when file closed, but other client changed it on server # # fs/cifs/inode.c # 2004/04/02 16:54:09-06:00 stevef@stevef95.austin.ibm.com +7 -2 # Invalidate readahead data properly when file closed, but other client changed it on server # # fs/cifs/file.c # 2004/04/02 16:54:09-06:00 stevef@stevef95.austin.ibm.com +20 -1 # Invalidate readahead data properly when file closed, but other client changed it on server # # ChangeSet # 2004/04/02 13:50:54-08:00 cifs.adm@hostme.bitkeeper.com # Merge bk://linux.bkbits.net/linux-2.5 # into hostme.bitkeeper.com:/repos/c/cifs/linux-2.5cifs # # fs/cifs/connect.c # 2004/04/02 13:50:48-08:00 cifs.adm@hostme.bitkeeper.com +0 -0 # Auto merged # # ChangeSet # 2004/04/01 18:39:11-06:00 stevef@stevef95.austin.ibm.com # Add missing description about how to specify credentials file # # fs/cifs/README # 2004/04/01 18:39:03-06:00 stevef@stevef95.austin.ibm.com +20 -2 # Add missing description about how to specify credentials file # # ChangeSet # 2004/03/26 16:32:07-06:00 stevef@stevef95.austin.ibm.com # clean up compiler warnings # # fs/cifs/file.c # 2004/03/26 16:31:59-06:00 stevef@stevef95.austin.ibm.com +7 -7 # clean up compiler warnings # # fs/cifs/cifssmb.c # 2004/03/26 16:31:59-06:00 stevef@stevef95.austin.ibm.com +1 -1 # clean up compiler warnings # # fs/cifs/cifsfs.c # 2004/03/26 16:31:59-06:00 stevef@stevef95.austin.ibm.com +2 -2 # clean up compiler warnings # # ChangeSet # 2004/03/25 18:34:51-06:00 stevef@stevef95.austin.ibm.com # fixes for fsx truncate/readahead/writebehind bug # # fs/cifs/inode.c # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +66 -105 # fixes for fsx truncate/readahead/writebehind bug # # fs/cifs/file.c # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +94 -40 # fixes for fsx truncate/readahead/writebehind bug # # fs/cifs/cifssmb.c # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +1 -1 # debug value missing # # fs/cifs/cifspdu.h # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +3 -3 # whitespace cleanup # # fs/cifs/cifsfs.h # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +0 -2 # fixes for fsx truncate/readahead/writebehind bug # # fs/cifs/cifsfs.c # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +12 -6 # fixes for fsx truncate/readahead/writebehind bug # # fs/cifs/CHANGES # 2004/03/25 18:31:04-06:00 stevef@stevef95.austin.ibm.com +3 -0 # update change log for cifs 1.05 # # ChangeSet # 2004/03/20 15:27:50-08:00 cifs.adm@hostme.bitkeeper.com # Merge bk://linux.bkbits.net/linux-2.5 # into hostme.bitkeeper.com:/repos/c/cifs/linux-2.5cifs # # fs/cifs/cifsfs.c # 2004/03/20 15:27:43-08:00 cifs.adm@hostme.bitkeeper.com +0 -0 # Auto merged # # ChangeSet # 2004/02/19 16:41:23-06:00 stevef@stevef95.austin.ibm.com # use safer i_size_write mechanism to update i_size # # ChangeSet # 2004/02/19 20:48:48-06:00 stevef@steveft21.ltcsamba # fix caching data integrity problem # # fs/cifs/inode.c # 2004/02/19 16:41:15-06:00 stevef@stevef95.austin.ibm.com +3 -3 # use safer i_size_write mechanism to update i_size # # fs/cifs/inode.c # 2004/02/19 20:48:30-06:00 stevef@steveft21.ltcsamba +7 -27 # fix caching data integrity problem and remove dead code # # fs/cifs/cifsfs.c # 2004/02/19 20:48:30-06:00 stevef@steveft21.ltcsamba +14 -12 # fix caching data integrity problem # # fs/cifs/CHANGES # 2004/02/19 20:48:30-06:00 stevef@steveft21.ltcsamba +7 -0 # update change log for 1.0.4 version # # fs/cifs/misc.c # 2004/02/19 16:41:16-06:00 stevef@stevef95.austin.ibm.com +0 -2 # remove dead code # # fs/cifs/file.c # 2004/02/19 16:41:15-06:00 stevef@stevef95.austin.ibm.com +13 -30 # use safer i_size_write mechanism to update i_size # # ChangeSet # 2004/02/18 09:20:18-08:00 cifs.adm@hostme.bitkeeper.com # Merge bk://linux.bkbits.net/linux-2.5 # into hostme.bitkeeper.com:/repos/c/cifs/linux-2.5cifs # # fs/cifs/file.c # 2004/02/18 09:20:13-08:00 cifs.adm@hostme.bitkeeper.com +0 -0 # Auto merged # # ChangeSet # 2004/02/17 15:59:49-06:00 stevef@stevef95.austin.ibm.com # Fix the exec, suid, dev mount parms to not log warnings when specified # # fs/cifs/connect.c # 2004/02/17 15:59:42-06:00 stevef@stevef95.austin.ibm.com +13 -9 # Fix the exec, suid, dev mount parms to not log warnings when specified # # ChangeSet # 2004/02/16 20:00:07-06:00 stevef@stevef95.austin.ibm.com # fix problem with inode revalidation and cache page invalidation # # fs/cifs/misc.c # 2004/02/16 19:57:28-06:00 stevef@stevef95.austin.ibm.com +4 -4 # cleanup smb header validation to avoid potential 32 bit overflow # # fs/cifs/inode.c # 2004/02/16 19:57:28-06:00 stevef@stevef95.austin.ibm.com +31 -5 # Fix revalidate code to invalidate remote inode more sanely # # fs/cifs/file.c # 2004/02/16 19:57:28-06:00 stevef@stevef95.austin.ibm.com +0 -1 # remove excessive inode page invalidation # # fs/cifs/connect.c # 2004/02/16 19:57:28-06:00 stevef@stevef95.austin.ibm.com +7 -4 # clean up demultiplex buffer checking description # # fs/cifs/README # 2004/02/16 19:57:28-06:00 stevef@stevef95.austin.ibm.com +22 -1 # update readme instructions # # fs/cifs/AUTHORS # 2004/02/16 19:57:28-06:00 stevef@stevef95.austin.ibm.com +2 -1 # update list of bug report submitters # # ChangeSet # 2004/02/10 11:41:26-06:00 stevef@smfhome.smfdom # allow nosuid mounts # # fs/cifs/connect.c # 2004/02/10 11:41:02-06:00 stevef@smfhome.smfdom +9 -0 # allow nosuid mounts # # ChangeSet # 2004/02/10 02:51:42-06:00 stevef@steveft21.ltcsamba # improve resume key resetting logic when filldir returns error and filename is in unicode # # fs/cifs/file.c # 2004/02/10 02:51:11-06:00 stevef@steveft21.ltcsamba +20 -24 # improve resume key resetting logic when filldir returns error and filename is in unicode # # ChangeSet # 2004/02/08 04:16:42-06:00 stevef@smfhome.smfdom # Spurious white space and duplicated line cleanup # # fs/cifs/connect.c # 2004/02/08 04:16:29-06:00 stevef@smfhome.smfdom +0 -4 # Spurious white space and duplicated line cleanup # # ChangeSet # 2004/02/06 17:37:36-06:00 stevef@steveft21.ltcsamba # ipv6 enablement for cifs vfs fixes # # fs/cifs/connect.c # 2004/02/06 17:37:19-06:00 stevef@steveft21.ltcsamba +14 -12 # ipv6 enablement for cifs vfs fixes # # ChangeSet # 2004/02/06 15:56:08-06:00 stevef@stevef95.austin.ibm.com # reset searches properly when filldir fails # # fs/cifs/transport.c # 2004/02/06 15:56:02-06:00 stevef@stevef95.austin.ibm.com +1 -1 # ipv6 missing structure # # fs/cifs/file.c # 2004/02/06 15:56:02-06:00 stevef@stevef95.austin.ibm.com +22 -4 # reset searches properly when filldir fails # # fs/cifs/cifsglob.h # 2004/02/06 15:56:01-06:00 stevef@stevef95.austin.ibm.com +5 -1 # ipv6 missing structure # # fs/cifs/CHANGES # 2004/02/06 15:56:01-06:00 stevef@stevef95.austin.ibm.com +3 -2 # Update cifs vfs changelog # # ChangeSet # 2004/02/06 12:25:38-06:00 stevef@stevef95.austin.ibm.com # fix problem not connecting to server when port not specified explicitly and port field unitialized # # fs/cifs/connect.c # 2004/02/06 12:25:24-06:00 stevef@stevef95.austin.ibm.com +76 -40 # fix problem not connecting to server when port not specified explicitly and port field unitialized # # fs/cifs/cifsglob.h # 2004/02/06 12:25:24-06:00 stevef@stevef95.austin.ibm.com +8 -1 # fix problem not connecting to server when port not specified explicitly and port field unitialized # # fs/cifs/CHANGES # 2004/02/06 12:25:24-06:00 stevef@stevef95.austin.ibm.com +5 -0 # Update cifs vfs change log for 1.0.3 # # ChangeSet # 2004/02/03 14:51:25-06:00 stevef@stevef95.austin.ibm.com # remove spurious debug messages # # fs/cifs/connect.c # 2004/02/03 14:51:18-06:00 stevef@stevef95.austin.ibm.com +2 -4 # remove spurious debug messages # # ChangeSet # 2004/02/02 17:54:45-06:00 stevef@stevef95.austin.ibm.com # fix remoting caching part 2 # # fs/cifs/misc.c # 2004/02/02 17:54:39-06:00 stevef@stevef95.austin.ibm.com +1 -1 # initialize smb buffer to zero # # fs/cifs/cifsfs.c # 2004/02/02 17:54:39-06:00 stevef@stevef95.austin.ibm.com +11 -10 # fix remoting caching part 2 # # ChangeSet # 2004/01/30 17:20:19-06:00 stevef@stevef95.austin.ibm.com # Relax requested CIFS permissions on open to simply request GENERIC_READ and GENERIC_WRITE (instead of GENERIC_ALL which # can unnecessarily conflict with share permissions by asking implicitly for take ownership and other unneeded flags) # # fs/cifs/file.c # 2004/01/30 17:20:13-06:00 stevef@stevef95.austin.ibm.com +12 -4 # Relax requested CIFS permissions on open to simply request GENERIC_READ and GENERIC_WRITE (instead of GENERIC_ALL which # can unnecessarily conflict with share permissions by asking implicitly for take ownership and other unneeded flags) # # fs/cifs/dir.c # 2004/01/30 17:20:13-06:00 stevef@stevef95.austin.ibm.com +7 -3 # Relax requested CIFS permissions on open to simply request GENERIC_READ and GENERIC_WRITE (instead of GENERIC_ALL which # can unnecessarily conflict with share permissions by asking implicitly for take ownership and other unneeded flags) # # ChangeSet # 2004/01/29 18:40:09-06:00 stevef@stevef95.austin.ibm.com # Fix caching problem with multiply open files from different clients # # fs/cifs/cifsfs.c # 2004/01/29 18:40:02-06:00 stevef@stevef95.austin.ibm.com +31 -4 # Fix caching problem with multiply open files from different clients # # fs/cifs/TODO # 2004/01/29 18:40:02-06:00 stevef@stevef95.austin.ibm.com +6 -10 # update to do list for cifs vfs # # fs/cifs/README # 2004/01/29 18:40:02-06:00 stevef@stevef95.austin.ibm.com +10 -0 # add missing description for mount option # # fs/cifs/CHANGES # 2004/01/29 18:40:02-06:00 stevef@stevef95.austin.ibm.com +9 -0 # update cifs vfs change log for version 1.0.2 # # ChangeSet # 2004/01/26 17:22:34-06:00 stevef@steveft21.ltcsamba # finish off mount parm sep override # # fs/cifs/connect.c # 2004/01/26 17:22:20-06:00 stevef@steveft21.ltcsamba +18 -5 # finish off mount parm sep override # # ChangeSet # 2004/01/23 22:34:13-06:00 stevef@steveft21.ltcsamba # finish handling commas in passwords # # fs/cifs/connect.c # 2004/01/23 22:33:57-06:00 stevef@steveft21.ltcsamba +7 -10 # finish handling commas in passwords # # ChangeSet # 2004/01/22 17:51:52-06:00 stevef@steveft21.ltcsamba # Allow null password string pointer and passwords longer than 16 bytes # # fs/cifs/smbencrypt.c # 2004/01/22 17:51:38-06:00 stevef@steveft21.ltcsamba +11 -6 # Allow null password string pointer and passwords longer than 16 bytes # # fs/cifs/misc.c # 2004/01/22 17:51:38-06:00 stevef@steveft21.ltcsamba +2 -0 # Allow null password string pointer and passwords longer than 16 bytes # # fs/cifs/connect.c # 2004/01/22 17:51:38-06:00 stevef@steveft21.ltcsamba +70 -23 # Allow null password string pointer and passwords longer than 16 bytes # # fs/cifs/cifsglob.h # 2004/01/22 17:51:38-06:00 stevef@steveft21.ltcsamba +1 -1 # Allow null password string pointer and passwords longer than 16 bytes # # fs/cifs/cifsencrypt.c # 2004/01/22 17:51:38-06:00 stevef@steveft21.ltcsamba +4 -5 # Allow null password string pointer and passwords longer than 16 bytes # # fs/cifs/CHANGES # 2004/01/22 17:51:38-06:00 stevef@steveft21.ltcsamba +4 -0 # update change log for cifs vfs # # ChangeSet # 2004/01/20 23:46:57-06:00 stevef@smfhome.smfdom # Check return on failed dentry allocation. Suggested by Randy Dunlap # # fs/cifs/file.c # 2004/01/20 23:44:53-06:00 stevef@smfhome.smfdom +5 -0 # Check return on failed dentry allocation. # # ChangeSet # 2004/01/08 17:17:13-06:00 stevef@stevef95.austin.ibm.com # Fix global kernel name space pollution # # fs/cifs/transport.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +1 -1 # Fix global kernel name space pollution # # fs/cifs/smbencrypt.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +0 -23 # Fix global kernel name space pollution # # fs/cifs/netmisc.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +1 -1 # Fix global kernel name space pollution # # fs/cifs/misc.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +4 -14 # Fix global kernel name space pollution # # fs/cifs/file.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +5 -3 # Fix global kernel name space pollution # # fs/cifs/connect.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +177 -163 # Fix global kernel name space pollution # # fs/cifs/cifssmb.c # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +37 -37 # Fix global kernel name space pollution # # fs/cifs/cifsproto.h # 2004/01/08 17:17:07-06:00 stevef@stevef95.austin.ibm.com +3 -22 # Fix global kernel name space pollution # # fs/cifs/cifsfs.c # 2004/01/08 17:17:06-06:00 stevef@stevef95.austin.ibm.com +10 -10 # Fix global kernel name space pollution # # fs/cifs/cifs_unicode.h # 2004/01/08 17:17:06-06:00 stevef@stevef95.austin.ibm.com +0 -15 # Fix global kernel name space pollution # # fs/cifs/cifs_unicode.c # 2004/01/08 17:17:06-06:00 stevef@stevef95.austin.ibm.com +0 -44 # Fix global kernel name space pollution # # ChangeSet # 2004/01/07 16:58:55-06:00 stevef@stevef95.austin.ibm.com # fix failed mounts to win98 part II # # fs/cifs/connect.c # 2004/01/07 16:58:48-06:00 stevef@stevef95.austin.ibm.com +1 -1 # fix failed mounts to win98 part II # # ChangeSet # 2004/01/06 17:55:00-06:00 stevef@stevef95.austin.ibm.com # gracefully exit on failed mounts to win98 (which closes tcp session rather than erroring on smb protocol negotiation) # # fs/cifs/transport.c # 2004/01/06 17:54:48-06:00 stevef@stevef95.austin.ibm.com +4 -0 # gracefully exit on failed mounts to win98 (which closes tcp session rather than erroring on smb protocol negotiation) # # fs/cifs/connect.c # 2004/01/06 17:54:48-06:00 stevef@stevef95.austin.ibm.com +18 -8 # gracefully exit on failed mounts to win98 (which closes tcp session rather than erroring on smb protocol negotiation) # # fs/cifs/cifssmb.c # 2004/01/06 17:54:48-06:00 stevef@stevef95.austin.ibm.com +8 -9 # fix white space # # fs/cifs/CHANGES # 2004/01/06 17:54:48-06:00 stevef@stevef95.austin.ibm.com +6 -0 # Update cifs change log for cifs 1.0.0 # # ChangeSet # 2004/01/06 10:05:09-06:00 stevef@steveft21.ltcsamba # fix cifs readme # # fs/cifs/README # 2004/01/06 10:04:56-06:00 stevef@steveft21.ltcsamba +8 -3 # fix cifs readme # # ChangeSet # 2003/12/11 09:14:24-06:00 stevef@steveft21.ltcsamba # set byte range locktimeouts properly # # fs/cifs/cifssmb.c # 2003/12/11 09:14:11-06:00 stevef@steveft21.ltcsamba +6 -4 # set byte range locktimeouts properly # # ChangeSet # 2003/12/08 11:00:47-06:00 stevef@steveft21.ltcsamba # Fix an incorrect mapping of open flags to cifs open disposition. Fix blocking byte range locks. These fix breakages that were notice running lock tests 1 and 7 of the connectathon posix file api tests # # fs/cifs/transport.c # 2003/12/08 11:00:34-06:00 stevef@steveft21.ltcsamba +4 -2 # Fix breakage in lock tests 1 and 7 of connectathon posix testing, due to invalid open disposition in one case in which create called when file exists, and problem with blocking lock operations # # fs/cifs/file.c # 2003/12/08 11:00:33-06:00 stevef@steveft21.ltcsamba +64 -49 # Fix breakage in lock test 7 of connectathon posix testing # # fs/cifs/dir.c # 2003/12/08 11:00:33-06:00 stevef@steveft21.ltcsamba +7 -7 # fix incorrect formatting # # fs/cifs/cifssmb.c # 2003/12/08 11:00:33-06:00 stevef@steveft21.ltcsamba +6 -1 # Fix breakage in lock test 7 of connectathon posix testing # # ChangeSet # 2003/12/06 11:21:50-06:00 stevef@steveft21.ltcsamba # allow disabling cifs Linux extensions via proc # # fs/cifs/connect.c # 2003/12/06 11:21:28-06:00 stevef@steveft21.ltcsamba +2 -0 # allow disabling cifs Linux extensions via proc # # fs/cifs/README # 2003/12/06 11:21:28-06:00 stevef@steveft21.ltcsamba +24 -14 # allow disabling cifs Linux extensions via proc # # fs/cifs/CHANGES # 2003/12/06 11:21:26-06:00 stevef@steveft21.ltcsamba +2 -1 # update change log for cifs vfs # # ChangeSet # 2003/12/05 10:46:56-06:00 stevef@steveft21.ltcsamba # Fix check of filldir return code during readdir to avoid incomplete search results displayed on very large directories. Fix cleanup of proc entries. Add config parm to allow disabling negotiating Linux extensions # # fs/cifs/file.c # 2003/12/05 10:46:37-06:00 stevef@steveft21.ltcsamba +86 -15 # Handle errors on filldir (e.g. for readdir problems on large directory searches or when memory constrained) # # fs/cifs/cifsglob.h # 2003/12/05 10:46:37-06:00 stevef@steveft21.ltcsamba +2 -0 # Fix cleanup of proc entries. Add config parm to allow disabling negotiating Linux extensions # # fs/cifs/cifsfs.c # 2003/12/05 10:46:37-06:00 stevef@steveft21.ltcsamba +1 -0 # Fix cleanup of proc entries. Add config parm to allow disabling negotiating Linux extensions # # fs/cifs/cifs_debug.c # 2003/12/05 10:46:36-06:00 stevef@steveft21.ltcsamba +67 -17 # Fix cleanup of proc entries. Add config parm to allow disabling negotiating Linux extensions # # ChangeSet # 2003/12/02 08:11:41-06:00 stevef@steveft21.ltcsamba # fix double incrementing of transaction counter # # fs/cifs/file.c # 2003/12/02 08:11:25-06:00 stevef@steveft21.ltcsamba +0 -9 # fix double incrementing of transaction counter # # ChangeSet # 2003/12/01 16:36:38-06:00 stevef@steveft21.ltcsamba # invalidate cached pages when last local instance closed so we do # not use stale data while someone may be modifying the file on the # server. # # fs/cifs/file.c # 2003/12/01 16:36:25-06:00 stevef@steveft21.ltcsamba +3 -2 # invalidate cached pages when last local instance closed so we do # not use stale data while someone may be modifying the file on the # server. # # fs/cifs/CHANGES # 2003/12/01 16:36:25-06:00 stevef@steveft21.ltcsamba +4 -3 # Update change log for cifs vfs # # ChangeSet # 2003/12/01 15:43:13-06:00 stevef@steveft21.ltcsamba # Oops on reopen files when dentry already freed # # fs/cifs/file.c # 2003/12/01 15:42:52-06:00 stevef@steveft21.ltcsamba +3 -3 # Oops on reopen files when dentry already freed # # ChangeSet # 2003/11/27 04:50:46-06:00 stevef@steveft21.ltcsamba # invalidate locally cached pages when server breaks oplock. Do not loop reconnecting for servers that drop tcp session rather than sending smb negprot response # # fs/cifs/connect.c # 2003/11/27 04:43:51-06:00 stevef@steveft21.ltcsamba +12 -1 # Do not reconnect session repeatedly for servers that drop tcp sessions rather than sending negprot response # # fs/cifs/cifsfs.c # 2003/11/27 04:43:51-06:00 stevef@steveft21.ltcsamba +4 -2 # invalidate locally cached pages when server breaks oplock # # fs/cifs/CHANGES # 2003/11/27 04:43:50-06:00 stevef@steveft21.ltcsamba +6 -0 # Update change log for cifs vfs 0.99 # # ChangeSet # 2003/11/25 17:09:03-06:00 stevef@stevef95.austin.ibm.com # rcvtimeout set improperly for some cifs servers # # fs/cifs/connect.c # 2003/11/25 17:08:57-06:00 stevef@stevef95.austin.ibm.com +7 -7 # rcvtimeout set improperly for some cifs servers # # fs/cifs/README # 2003/11/25 17:08:57-06:00 stevef@stevef95.austin.ibm.com +8 -7 # typo in cifs README # # ChangeSet # 2003/11/21 17:26:27-06:00 stevef@stevef95.austin.ibm.com # missing message on timed out requests # # fs/cifs/cifssmb.c # 2003/11/21 17:26:21-06:00 stevef@stevef95.austin.ibm.com +3 -2 # missing message on timed out requests # # ChangeSet # 2003/11/20 19:27:13-06:00 stevef@stevef95.austin.ibm.com # Avoid smb data corruption under heavy stress # # fs/cifs/transport.c # 2003/11/20 19:24:54-06:00 stevef@stevef95.austin.ibm.com +7 -2 # Avoid smb data corruption under heavy stress # # fs/cifs/file.c # 2003/11/20 19:24:54-06:00 stevef@stevef95.austin.ibm.com +2 -0 # Avoid smb data corruption under heavy stress # # fs/cifs/dir.c # 2003/11/20 19:24:54-06:00 stevef@stevef95.austin.ibm.com +1 -0 # Avoid smb data corruption under heavy stress # # fs/cifs/connect.c # 2003/11/20 19:24:54-06:00 stevef@stevef95.austin.ibm.com +1 -0 # Avoid smb data corruption under heavy stress # # fs/cifs/CHANGES # 2003/11/20 19:24:54-06:00 stevef@stevef95.austin.ibm.com +4 -1 # update change log for 0.9.8 cifs vfs # # ChangeSet # 2003/11/19 11:24:43-06:00 stevef@linux-udp14619769uds.austin.ibm.com # Fix oops in mount error path when unload_nls called with bad pointer. # # ChangeSet # 2003/11/19 17:32:27-06:00 stevef@stevef95.austin.ibm.com # Do not grab i_sem (already taken in filemap.c across commit write calls) during reopen of invalidated file handle. # # fs/cifs/file.c # 2003/11/19 17:32:21-06:00 stevef@stevef95.austin.ibm.com +5 -5 # Do not grab i_sem (already taken in filemap.c across commit write calls) during reopen of invalidated file handle. # # fs/cifs/cifsglob.h # 2003/11/19 17:32:21-06:00 stevef@stevef95.austin.ibm.com +2 -1 # Do not grab i_sem (already taken in filemap.c across commit write calls) during reopen of invalidated file handle. # # fs/cifs/cifsfs.c # 2003/11/19 11:24:19-06:00 stevef@linux-udp14619769uds.austin.ibm.com +3 -0 # Fix oops in mount error path when unload_nls called with bad pointer. # # fs/cifs/CHANGES # 2003/11/19 11:24:19-06:00 stevef@linux-udp14619769uds.austin.ibm.com +5 -0 # Fix oops in mount error path when unload_nls called with bad pointer. # # ChangeSet # 2003/11/18 17:48:08-06:00 stevef@stevef95.austin.ibm.com # Missing soft vs. hard retry mount option # # fs/cifs/connect.c # 2003/11/18 17:48:02-06:00 stevef@stevef95.austin.ibm.com +26 -3 # Missing soft vs. hard retry mount option # # fs/cifs/cifssmb.c # 2003/11/18 17:48:02-06:00 stevef@stevef95.austin.ibm.com +11 -7 # Missing soft vs. hard retry mount option # # fs/cifs/cifsglob.h # 2003/11/18 17:48:02-06:00 stevef@stevef95.austin.ibm.com +5 -0 # Missing soft vs. hard retry mount option # # ChangeSet # 2003/11/16 21:52:41-06:00 stevef@steveft21.austin.ibm.com # Fix compile error # # fs/cifs/cifssmb.c # 2003/11/16 21:52:29-06:00 stevef@steveft21.austin.ibm.com +4 -2 # Fix compile error # # ChangeSet # 2003/11/14 16:42:04-06:00 stevef@stevef95.austin.ibm.com # correct retry on remaining handles based calls # # fs/cifs/inode.c # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +2 -2 # correct retry on remaining handles based calls # # fs/cifs/file.c # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +19 -12 # correct retry on remaining handles based calls # # fs/cifs/connect.c # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +2 -0 # correct retry on remaining handles based calls # # fs/cifs/cifssmb.c # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +23 -0 # correct retry on remaining handles based calls # # fs/cifs/cifsglob.h # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +3 -0 # correct retry on remaining handles based calls # # fs/cifs/cifsfs.c # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +18 -6 # correct retry on remaining handles based calls # # fs/cifs/cifs_debug.c # 2003/11/14 16:41:54-06:00 stevef@stevef95.austin.ibm.com +23 -1 # Update debugging code for session reconnection info # # ChangeSet # 2003/11/12 13:10:10-06:00 stevef@stevef95.austin.ibm.com # finish off move from reopening all files on reconnection (which takes too long under heavy stress) to reopen file as needed after reconnection to server. # # fs/cifs/file.c # 2003/11/12 13:09:59-06:00 stevef@stevef95.austin.ibm.com +144 -169 # finish off move from reopening all files on reconnection (which takes too long under heavy stress) to reopen file as needed after reconnection to server. # # fs/cifs/cifssmb.c # 2003/11/12 13:09:59-06:00 stevef@stevef95.austin.ibm.com +26 -8 # finish off move from reopening all files on reconnection (which takes too long under heavy stress) to reopen file as needed after reconnection to server. # # fs/cifs/cifsproto.h # 2003/11/12 13:09:59-06:00 stevef@stevef95.austin.ibm.com +0 -1 # finish off move from reopening all files on reconnection (which takes too long under heavy stress) to reopen file as needed after reconnection to server. # # fs/cifs/cifsglob.h # 2003/11/12 13:09:59-06:00 stevef@stevef95.austin.ibm.com +0 -1 # finish off move from reopening all files on reconnection (which takes too long under heavy stress) to reopen file as needed after reconnection to server. # # ChangeSet # 2003/11/11 17:51:40-06:00 stevef@stevef95.austin.ibm.com # have to reconnect open files safely, one at a time, as needed # # fs/cifs/transport.c # 2003/11/11 17:51:24-06:00 stevef@stevef95.austin.ibm.com +0 -3 # have to reconnect open files safely, one at a time, as needed # # fs/cifs/inode.c # 2003/11/11 17:51:24-06:00 stevef@stevef95.austin.ibm.com +24 -7 # have to reconnect open files safely, one at a time, as needed # # fs/cifs/file.c # 2003/11/11 17:51:24-06:00 stevef@stevef95.austin.ibm.com +15 -3 # have to reconnect open files safely, one at a time, as needed # # fs/cifs/connect.c # 2003/11/11 17:51:23-06:00 stevef@stevef95.austin.ibm.com +3 -2 # have to reconnect open files safely, one at a time, as needed # # fs/cifs/cifssmb.c # 2003/11/11 17:51:23-06:00 stevef@stevef95.austin.ibm.com +79 -42 # have to reconnect open files safely, one at a time, as needed # # fs/cifs/cifsglob.h # 2003/11/11 17:51:23-06:00 stevef@stevef95.austin.ibm.com +1 -0 # have to reconnect open files safely, one at a time, as needed # # ChangeSet # 2003/11/10 00:57:19-06:00 stevef@steveft21.austin.ibm.com # fix endian bug in lockingX and add retry on EAGAIN # # fs/cifs/transport.c # 2003/11/10 00:56:55-06:00 stevef@steveft21.austin.ibm.com +1 -1 # typo in retry # # fs/cifs/cifssmb.c # 2003/11/10 00:56:55-06:00 stevef@steveft21.austin.ibm.com +151 -26 # fix endian bug in lockingX and add retry on EAGAIN # # fs/cifs/cifspdu.h # 2003/11/10 00:56:55-06:00 stevef@steveft21.austin.ibm.com +4 -2 # fix endian bug in lockingX # # fs/cifs/CHANGES # 2003/11/10 00:56:55-06:00 stevef@steveft21.austin.ibm.com +5 -0 # update cifs vfs change log # # ChangeSet # 2003/11/04 17:46:07-06:00 stevef@stevef95.austin.ibm.com # move bad smb session retry to correct location, up one level in cifs vfs code # # fs/cifs/transport.c # 2003/11/04 17:46:01-06:00 stevef@stevef95.austin.ibm.com +39 -39 # move bad smb session retry to correct location, up one level in cifs vfs code # # ChangeSet # 2003/11/03 23:17:47-06:00 stevef@smfhome.smfdom # Do not return buffer if request has already timed out. # # fs/cifs/transport.c # 2003/11/03 23:15:09-06:00 stevef@smfhome.smfdom +19 -7 # Do not return buffer if request has already timed out. # # fs/cifs/connect.c # 2003/11/03 23:15:09-06:00 stevef@smfhome.smfdom +1 -1 # Do not return buffer if request has already timed out. # # ChangeSet # 2003/11/03 18:36:00-06:00 stevef@stevef95.austin.ibm.com # Merge bk://cifs.bkbits.net/linux-2.5cifs # into stevef95.austin.ibm.com:/home/stevef/bk/linux-2.5cifs # # fs/cifs/connect.c # 2003/11/03 18:35:52-06:00 stevef@stevef95.austin.ibm.com +0 -0 # Auto merged # # ChangeSet # 2003/11/03 18:30:25-06:00 stevef@stevef95.austin.ibm.com # fix to not retime out the same session twice since it can invalidate the newly reestablished session unnecessarily # # fs/cifs/transport.c # 2003/11/03 18:30:19-06:00 stevef@stevef95.austin.ibm.com +9 -4 # fix to not retime out the same session twice since it can invalidate the newly reestablished session unnecessarily # # fs/cifs/file.c # 2003/11/03 18:30:19-06:00 stevef@stevef95.austin.ibm.com +7 -4 # Fix oops when invalid inode in reopening dentry # # fs/cifs/connect.c # 2003/11/03 18:30:19-06:00 stevef@stevef95.austin.ibm.com +19 -0 # fix to not retime out the same session twice since it can invalidate the newly reestablished session unnecessarily # # fs/cifs/cifsglob.h # 2003/11/03 18:30:19-06:00 stevef@stevef95.austin.ibm.com +1 -0 # fix to not retime out the same session twice since it can invalidate the newly reestablished session unnecessarily # # fs/cifs/cifsfs.c # 2003/11/03 18:30:19-06:00 stevef@stevef95.austin.ibm.com +1 -1 # oplock thread can sleep too long when multiple oplock requests come in at the same time # # ChangeSet # 2003/11/02 23:44:48-06:00 stevef@linux.local # Fix EIO caused by network timeouts on changing file size. # 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 # # fs/cifs/inode.c # 2003/11/02 23:44:42-06:00 stevef@linux.local +68 -26 # 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 # # ChangeSet # 2003/11/02 14:58:15-06:00 stevef@linux.local # fix oops in send_sig on unmount of cifs vfs due to sending signal to demultiplex thread after it has exited. # Do not treat invalid handle warning in response to oplock break (of file that is now closed) as an error. # # fs/cifs/misc.c # 2003/11/02 14:55:37-06:00 stevef@linux.local +18 -2 # Do not treat invalid handle on oplock break as an error. After writing out dirty file data for file that has been cached locally it is harmless for close and response to oplock break to be sent out of order # # fs/cifs/connect.c # 2003/11/02 14:55:37-06:00 stevef@linux.local +2 -3 # fix oops in send_sig on unmount of cifs vfs due to sending signal to demultiplex thread after it has exited # # fs/cifs/CHANGES # 2003/11/02 14:55:37-06:00 stevef@linux.local +7 -1 # Update cifs change log # # ChangeSet # 2003/10/30 16:39:04-06:00 stevef@stevef95.austin.ibm.com # Fix invalid dentry when race in mkdir between two clients # # fs/cifs/inode.c # 2003/10/30 16:36:52-06:00 stevef@stevef95.austin.ibm.com +1 -0 # Fix invalid dentry when race in mkdir between two clients # # fs/cifs/CHANGES # 2003/10/30 16:36:52-06:00 stevef@stevef95.austin.ibm.com +2 -1 # Update cifs change log # # ChangeSet # 2003/10/28 17:44:29-06:00 stevef@linux.local # Fix problem reconnecting additional mounts to the same server after # session failure. # # fs/cifs/cifssmb.c # 2003/10/28 17:44:14-06:00 stevef@linux.local +2 -2 # Fix problem reconnecting additional mounts to the same server after # session failure. # # fs/cifs/CHANGES # 2003/10/28 17:44:14-06:00 stevef@linux.local +2 -0 # Update cifs change log # # ChangeSet # 2003/10/27 16:50:37-06:00 stevef@linux.local # Can not mount from cifs vfs client built with gcc 3.3.1 due to compiler optimization of unsafe global variable. Remove unsafe global variable. # # fs/cifs/smbencrypt.c # 2003/10/27 16:50:06-06:00 stevef@linux.local +0 -116 # Remove broken lmv2 encrypt functions # # fs/cifs/md4.c # 2003/10/27 16:50:06-06:00 stevef@linux.local +28 -34 # Can not mount from cifs vfs client built with gcc 3.3.1 due to compiler optimization of unsafe global variable. Remove unsafe global variable. # # fs/cifs/cifsglob.h # 2003/10/27 16:50:06-06:00 stevef@linux.local +3 -3 # text beyond 80 chars # # fs/cifs/README # 2003/10/27 16:50:06-06:00 stevef@linux.local +77 -56 # Update cifs vfs readme to fix formatting to be readable and correct mount helper writeup # # fs/cifs/CHANGES # 2003/10/27 16:50:05-06:00 stevef@linux.local +4 -0 # Update cifs vfs change log for 0.9.5 # diff -Nru a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS --- a/fs/cifs/AUTHORS Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/AUTHORS Wed Apr 21 00:30:29 2004 @@ -26,5 +26,6 @@ ------------------------------------- Thanks to those in the community who have submitted detailed bug reports and debug of problems they have found: Jochen Dolze, David Blaine, -Rene Scharfe, Martin Josefsson, Alexander Wild and others. +Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori, +Urban Widmark, Massimiliano Ferrero, Howard Owen and others. diff -Nru a/fs/cifs/CHANGES b/fs/cifs/CHANGES --- a/fs/cifs/CHANGES Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/CHANGES Wed Apr 21 00:30:29 2004 @@ -1,3 +1,101 @@ +Version 1.09 +------------ +Fix /proc/fs module unload warning message (that could be logged +to the kernel log). Fix intermittent failure in connectathon +test7 (hardlink count not immediately refreshed in case in which +inode metadata can be incorrectly kept cached when time near zero) + +Version 1.08 +------------ +Allow file_mode and dir_mode (specified at mount time) to be enforced +locally (the server already enforced its own ACLs too) for servers +that do not report the correct mode (do not support the +CIFS Unix Extensions). + +Version 1.07 +------------ +Fix some small memory leaks in some unmount error paths. Fix major leak +of cache pages in readpages causing multiple read oriented stress +testcases (including fsx, and even large file copy) to fail over time. + +Version 1.06 +------------ +Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated with server. +This allows files that differ only in case and improves performance of file +creation and file open to such servers. Fix semaphore conflict which causes +slow delete of open file to Samba (which unfortunately can cause an oplock +break to self while vfs_unlink held i_sem) which can hang for 20 seconds. + +Version 1.05 +------------ +fixes to cifs_readpages for fsx test case + +Version 1.04 +------------ +Fix caching data integrity bug when extending file size especially when no +oplock on file. Fix spurious logging of valid already parsed mount options +that are parsed outside of the cifs vfs such as nosuid. + + +Version 1.03 +------------ +Connect to server when port number override not specified, and tcp port +unitialized. Reset search to restart at correct file when kernel routine +filldir returns error during large directory searches (readdir). + +Version 1.02 +------------ +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 +options. + +Version 1.01 +------------ +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 +embedded commas in mount parsing of passwords. + +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 -Nru a/fs/cifs/Makefile b/fs/cifs/Makefile --- a/fs/cifs/Makefile Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/Makefile Wed Apr 21 00:30:29 2004 @@ -3,4 +3,4 @@ # obj-$(CONFIG_CIFS) += cifs.o -cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o +cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o diff -Nru a/fs/cifs/README b/fs/cifs/README --- a/fs/cifs/README Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/README Wed Apr 21 00:30:29 2004 @@ -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,105 @@ 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 + +Note that when the mount.cifs utility is run suid (allowing user mounts), +in order to reduce risks, the "nosuid" mount flag is passed in on mount to +disallow execution of an suid program mounted on the remote target. +When mount is executed as root, nosuid is not passed in by default, +and execution of suid programs on the remote target would be enabled +by default. This can be changed, as with nfs and other filesystems, +by simply specifying "nosuid" among the mount options. For user mounts +though to be able to pass the suid flag to mount requires rebuilding +mount.cifs with the following flag: + + gcc samba/source/client/mount.cifs.c -DCIFS_ALLOW_USR_SUID -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: + +Before -o the option -v may be specified to make the mount.cifs +mount helper display the mount steps more verbosely. +After -o the following commonly used 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 + +Other cifs mount options are described below. Use of TCP names (in addition to +ip addresses) is available if the mount helper (mount.cifs) is installed. If +you do not trust the server to which are mounted, or if you do not have +cifs signing enabled (and the physical network is insecure), consider use +of the standard mount options "noexec" and "nosuid" to reduce the risk of +running an altered binary on your local system (downloaded from a hostile server +or altered by a hostile router). + +When using the mount helper mount.cifs, passwords may be specified via alternate +mechanisms, instead of specifying it after -o using the normal "pass=" syntax +on the command line: +1) By including it in a credential file. Specify credentials=filename as one +of the mount options. Credential files contain two lines + username=someuser + password=your_password +2) By specifying the password in the PASSWD environment variable (similarly +the user name can be taken from the USER environment variable). + +If no password is provided, mount.cifs will prompt for password entry 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 ====================== @@ -141,54 +190,91 @@ ro mount network share read-only version used to distinguish different versions of the mount helper utility (not typically needed) + sep if first mount option (after the -o), overrides + the comma as the separator between the mount + parms. e.g. + -o user=myname,password=mypassword,domain=mydom + could be passed instead with period as the separator by + -o sep=.user=myname.password=mypassword.domain=mydom + this might be useful when comma is contained within username + or password or domain. This option is less important + when the cifs mount helper cifs.mount (version 1.1 or later) + is used. + nosuid Do not allow remote executables with the suid bit + program to be executed. This is only meaningful for mounts + to servers such as Samba which support the CIFS Unix Extensions. + If you do not trust the servers in your network (your mount + targets) it is recommended that you specify this option for + greater security. + suid Allow remote files on this mountpoint with suid enabled to + be executed (default for mounts when executed as root, + nosuid is default for user mounts). + credentials (allow valid when the cifs mount helper, mount.cifs, is + installed. Specifies the name of the credential file which + will be read to obtain the userid and password. 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. (default 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). diff -Nru a/fs/cifs/TODO b/fs/cifs/TODO --- a/fs/cifs/TODO Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/TODO Wed Apr 21 00:30:29 2004 @@ -1,4 +1,4 @@ -version 0.8.1 July 4th, 2003 +version 1.0.2 January 29, 2004 A Partial List of Known Problems and Missing Features ===================================================== @@ -27,8 +27,8 @@ f) Directory entry caching relies on a 1 second timer, rather than using FindNotify or equivalent. - (started) -g) There may be a few additional changes that could be done to take advantage -of recent 2.5 kernel improvements in byte-range locking +g) A few byte range testcases fail due to POSIX vs. Windows/CIFS +style byte range lock differences h) quota support @@ -36,8 +36,6 @@ which will allow us to expose dos attributes as well as real ACLs -j) finish off the mount helper, mount.cifs - (started) - k) finish writepages support (multi-page write behind for improved performance) and syncpage @@ -56,17 +54,15 @@ at a time when 8 pages or more are requested. -KNOWN BUGS (updated July 4th, 2003) +KNOWN BUGS (updated January 30, 2004) ==================================== 1) existing symbolic links (Windows reparse points) are recognized but can not be created remotely. They are implemented for Samba and those that support the CIFS Unix extensions but Samba has a bug currently handling symlink text beginning with slash -2) delete of file with read-only attribute set will fail (may be ok) -3) mount helper syntax not quite matching man page -4) follow_link and readdir code does not follow dfs junctions +2) follow_link and readdir code does not follow dfs junctions but recognizes them -5) create of new files to FAT partitions on Windows servers can +3) create of new files to FAT partitions on Windows servers can succeed but still return access denied (appears to be Windows not client problem). NTFS partitions do not have this problem. diff -Nru a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c --- a/fs/cifs/cifs_debug.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/cifs_debug.c Wed Apr 21 00:30:29 2004 @@ -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; } @@ -281,14 +310,17 @@ remove_proc_entry("DebugData", proc_fs_cifs); remove_proc_entry("cifsFYI", proc_fs_cifs); - remove_proc_entry("TraceSMB", 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); } @@ -406,6 +438,46 @@ quotaEnabled = 0; else if (c == '1' || c == 'y' || c == 'Y') quotaEnabled = 1; + + 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; } diff -Nru a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c --- a/fs/cifs/cifs_unicode.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/cifs_unicode.c Wed Apr 21 00:30:29 2004 @@ -25,25 +25,6 @@ #include "cifs_debug.h" /* - * NAME: toUpper() - * - * FUNCTION: Upper case ASCII string (in place) using the current codepage - * - */ - -void -toUpper(const struct nls_table *n, char *mixed_string) -{ - unsigned int i; - char temp; - - for (i = 0; i < strlen(mixed_string); i++) { - temp = mixed_string[i]; - mixed_string[i] = n->charset2upper[(int) temp]; - } -} - -/* * NAME: cifs_strfromUCS() * * FUNCTION: Convert little-endian unicode string to character string @@ -104,28 +85,3 @@ return i; } -/* - * NAME: get_UCSname2() - * - * FUNCTION: Allocate and translate to unicode string - * - */ -/*int -get_UCSname2(struct component_name *uniName, struct dentry *dentry, - struct nls_table *nls_tab) -{ - int length = dentry->d_name.len; - - if (length > 255) - return ENAMETOOLONG; - - uniName->name = kmalloc((length + 1) * sizeof (wchar_t), GFP_KERNEL); - - if (uniName->name == NULL) - return ENOSPC; - - uniName->namlen = cifs_strtoUCS(uniName->name, dentry->d_name.name, - length, nls_tab); - - return 0; -} */ diff -Nru a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h --- a/fs/cifs/cifs_unicode.h Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/cifs_unicode.h Wed Apr 21 00:30:29 2004 @@ -58,25 +58,10 @@ extern struct UniCaseRange UniLowerRange[]; #endif /* UNIUPR_NOLOWER */ -/* - * directory entry argument - */ -struct component_name { - int namlen; - wchar_t *name; -}; - #ifdef __KERNEL__ int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *); int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *); - -int cifs_UCSname(struct component_name *, struct dentry *, - const struct nls_table *); - -void toUpper(const struct nls_table *, char *); #endif - -#define free_UCSname(COMP) kfree((COMP)->name) /* * UniStrcat: Concatenate the second string to the first diff -Nru a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c --- a/fs/cifs/cifsencrypt.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/cifsencrypt.c Wed Apr 21 00:30:29 2004 @@ -74,7 +74,7 @@ rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature); if(rc) - memset(cifs_pdu->Signature.SecuritySignature, 0, 8); + memset(cifs_pdu->Signature.SecuritySignature, 0, 8); else memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); @@ -88,15 +88,15 @@ char server_response_sig[8]; char what_we_think_sig_should_be[20]; - if((cifs_pdu == NULL) || (mac_key == NULL)) - return -EINVAL; + if((cifs_pdu == NULL) || (mac_key == NULL)) + return -EINVAL; if (cifs_pdu->Command == SMB_COM_NEGOTIATE) return 0; if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu; - if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) + if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) return 0; } @@ -113,10 +113,10 @@ its signature against what the server sent */ memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8); - cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number; - cifs_pdu->Signature.Sequence.Reserved = 0; + cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number; + cifs_pdu->Signature.Sequence.Reserved = 0; - rc = cifs_calculate_signature(cifs_pdu, mac_key, + rc = cifs_calculate_signature(cifs_pdu, mac_key, what_we_think_sig_should_be); if(rc) @@ -136,7 +136,7 @@ int cifs_calculate_mac_key(char * key, const char * rn, const char * password) { char temp_key[16]; - if ((key == NULL) || (rn == NULL) || (password == NULL)) + if ((key == NULL) || (rn == NULL)) return -EINVAL; E_md4hash(password, temp_key); @@ -156,7 +156,7 @@ if(ses) return -EINVAL; - E_md4hash(ses->password_with_pad, temp_hash); + E_md4hash(ses->password, temp_hash); hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); user_name_len = strlen(ses->userName); @@ -165,22 +165,21 @@ dom_name_len = strlen(ses->domainName); if(dom_name_len > MAX_USERNAME_SIZE) return -EINVAL; - - + ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); - unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); - + unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); + for(i=0;icharset2upper[(int)ses->userName[i]]; ucase_buf[i] = 0; - user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); + user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); unicode_buf[user_name_len] = 0; user_name_len++; - for(i=0;icharset2upper[(int)ses->domainName[i]]; - ucase_buf[i] = 0; - dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); + for(i=0;icharset2upper[(int)ses->domainName[i]]; + ucase_buf[i] = 0; + dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); unicode_buf[user_name_len + dom_name_len] = 0; hmac_md5_update((const unsigned char *) unicode_buf, @@ -200,7 +199,6 @@ hmac_md5_update(ses->server->cryptKey,8,&context); /* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ - hmac_md5_final(v2_session_response,&context); } diff -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c --- a/fs/cifs/cifsfs.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/cifsfs.c Wed Apr 21 00:30:29 2004 @@ -1,7 +1,7 @@ /* * fs/cifs/cifsfs.c * - * Copyright (C) International Business Machines Corp., 2002,2003 + * Copyright (C) International Business Machines Corp., 2002,2004 * Author(s): Steve French (sfrench@us.ibm.com) * * Common Internet FileSystem (CIFS) client @@ -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; @@ -82,6 +83,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); @@ -123,14 +127,15 @@ iput(inode); out_mount_failed: - if(cifs_sb->local_nls) - unload_nls(cifs_sb->local_nls); - if(cifs_sb) + if(cifs_sb) { + if(cifs_sb->local_nls) + unload_nls(cifs_sb->local_nls); kfree(cifs_sb); + } return rc; } -void +static void cifs_put_super(struct super_block *sb) { int rc = 0; @@ -151,7 +156,7 @@ return; } -int +static int cifs_statfs(struct super_block *sb, struct kstatfs *buf) { int xid, rc; @@ -186,8 +191,21 @@ static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd) { - /* the server does permission checks, we do not need to do it here */ - return 0; + struct cifs_sb_info *cifs_sb; + + cifs_sb = CIFS_SB(inode->i_sb); + + if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { + /* the server supports the Unix-like mode bits and does its + own permission checks, and therefore we do not allow the file + mode to be overriden on these mounts - so do not do perm + check on client side */ + return 0; + } else /* file mode might have been restricted at mount time + on the client (above and beyond ACL on servers) for + servers which do not support setting and viewing mode bits, + so allowing client to check permissions is useful */ + return vfs_permission(inode, mask); } static kmem_cache_t *cifs_inode_cachep; @@ -402,24 +420,58 @@ return sb; } -ssize_t +static ssize_t cifs_read_wrapper(struct file * file, char *read_data, size_t read_size, loff_t * poffset) { - if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) + if(file == NULL) + return -EIO; + else if(file->f_dentry == NULL) + return -EIO; + else if(file->f_dentry->d_inode == NULL) + return -EIO; + + cFYI(1,("In read_wrapper size %zd at %lld",read_size,*poffset)); + if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) { return generic_file_read(file,read_data,read_size,poffset); - else - return cifs_read(file,read_data,read_size,poffset); + } else { + /* BB do we need to lock inode from here until after invalidate? */ +/* if(file->f_dentry->d_inode->i_mapping) { + filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); + filemap_fdatawait(file->f_dentry->d_inode->i_mapping); + }*/ +/* cifs_revalidate(file->f_dentry);*/ /* BB fixme */ + + /* BB we should make timer configurable - perhaps + by simply calling cifs_revalidate here */ + /* invalidate_remote_inode(file->f_dentry->d_inode);*/ + return generic_file_read(file,read_data,read_size,poffset); + } } -ssize_t +static ssize_t cifs_write_wrapper(struct file * file, const char *write_data, size_t write_size, loff_t * poffset) { - if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) /* check caching for write */ - return generic_file_write(file,write_data, write_size,poffset); - else - return cifs_write(file,write_data,write_size,poffset); + ssize_t written; + + if(file == NULL) + return -EIO; + else if(file->f_dentry == NULL) + return -EIO; + else if(file->f_dentry->d_inode == NULL) + return -EIO; + + cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset)); + + /* check whether we can cache writes locally */ + written = generic_file_write(file,write_data,write_size,poffset); + if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) { + if(file->f_dentry->d_inode->i_mapping) { + filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); + } + } + return written; } @@ -476,8 +528,8 @@ }; struct file_operations cifs_file_ops = { - .read = generic_file_read, - .write = generic_file_write, + .read = cifs_read_wrapper, + .write = cifs_write_wrapper, .open = cifs_open, .release = cifs_close, .lock = cifs_lock, @@ -485,12 +537,18 @@ .flush = cifs_flush, .mmap = cifs_file_mmap, .sendfile = generic_file_sendfile, +#ifdef CIFS_FCNTL + .fcntl = cifs_fcntl, +#endif }; struct file_operations cifs_dir_ops = { .readdir = cifs_readdir, .release = cifs_closedir, .read = generic_read_dir, +#ifdef CIFS_FCNTL + .fcntl = cifs_fcntl, +#endif }; static void @@ -505,7 +563,7 @@ } } -int +static int cifs_init_inodecache(void) { cifs_inode_cachep = kmem_cache_create("cifs_inode_cache", @@ -518,14 +576,14 @@ return 0; } -void +static void cifs_destroy_inodecache(void) { if (kmem_cache_destroy(cifs_inode_cachep)) printk(KERN_WARNING "cifs_inode_cache: error freeing\n"); } -int +static int cifs_init_request_bufs(void) { cifs_req_cachep = kmem_cache_create("cifs_request", @@ -538,7 +596,7 @@ return 0; } -void +static void cifs_destroy_request_bufs(void) { if (kmem_cache_destroy(cifs_req_cachep)) @@ -546,7 +604,7 @@ "cifs_destroy_request_cache: error not all structures were freed\n"); } -int +static int cifs_init_mids(void) { cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", @@ -565,7 +623,7 @@ return 0; } -void +static void cifs_destroy_mids(void) { if (kmem_cache_destroy(cifs_mid_cachep)) @@ -591,7 +649,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); @@ -600,23 +658,41 @@ oplock_item = list_entry(GlobalOplock_Q.next, struct oplock_q_entry, qhead); if(oplock_item) { + cFYI(1,("found oplock item to write out")); pTcon = oplock_item->tcon; inode = oplock_item->pinode; netfid = oplock_item->netfid; spin_unlock(&GlobalMid_Lock); DeleteOplockQEntry(oplock_item); - if (S_ISREG(inode->i_mode)) + /* can not grab inode sem here since it would + deadlock when oplock received on delete + since vfs_unlink holds the i_sem across + the call */ + /* down(&inode->i_sem);*/ + 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; + /* up(&inode->i_sem);*/ 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); } @@ -640,6 +716,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 -Nru a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h --- a/fs/cifs/cifsfs.h Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/cifsfs.h Wed Apr 21 00:30:29 2004 @@ -60,8 +60,6 @@ extern int cifs_setattr(struct dentry *, struct iattr *); extern struct inode_operations cifs_file_inode_ops; -extern void cifs_truncate_file(struct inode *); - extern struct inode_operations cifs_symlink_inode_ops; /* Functions related to files and directories */ @@ -80,6 +78,7 @@ extern struct file_operations cifs_dir_ops; extern int cifs_dir_open(struct inode *inode, struct file *file); extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); +extern long cifs_fcntl(int, unsigned int, unsigned long, struct file *); /* Functions related to dir entries */ extern struct dentry_operations cifs_dentry_ops; diff -Nru a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h --- a/fs/cifs/cifsglob.h Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/cifsglob.h Wed Apr 21 00:30:29 2004 @@ -16,6 +16,7 @@ * */ #include +#include #include "cifs_fs_sb.h" /* * The sizes of various internal tables and strings @@ -55,6 +56,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. * @@ -83,6 +88,13 @@ Kerberos /* Kerberos via SPNEGO */ }; +enum protocolEnum { + IPV4 = 0, + IPV6, + SCTP + /* Netbios frames protocol not supported at this time */ +}; + /* ***************************************************************** * Except the CIFS PDUs themselves all the @@ -94,13 +106,16 @@ 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 */ struct socket *ssocket; - struct sockaddr_in sockAddr; + union { + struct sockaddr_in sockAddr; + struct sockaddr_in6 sockAddr6; + } addr; wait_queue_head_t response_q; 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 svType; /* computer type */ + enum protocolEnum protocolType; char versionMajor; char versionMinor; int svlocal:1; /* local server or remote */ @@ -161,7 +176,7 @@ char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */ char userName[MAX_USERNAME_SIZE + 1]; char domainName[MAX_USERNAME_SIZE + 1]; - char password_with_pad[CIFS_ENCPWD_SIZE]; + char * password; }; /* @@ -175,13 +190,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 +229,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 +291,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 +331,7 @@ * ---------- * sesSem operations on smb session * tconSem operations on tree connection - * i_sem inode operations + * fh_sem file handle reconnection operations * ****************************************************************************/ @@ -358,6 +376,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 +395,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 -Nru a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h --- a/fs/cifs/cifspdu.h Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/cifspdu.h Wed Apr 21 00:30:29 2004 @@ -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 @@ -1101,10 +1103,10 @@ } TRANSACTION2_SPI_RSP; struct set_file_rename { - __u32 overwrite; /* 1 = overwrite dest */ - __u32 root_fid; /* zero */ + __u32 overwrite; /* 1 = overwrite dest */ + __u32 root_fid; /* zero */ __u32 target_name_len; - char target_name[0]; /* Must be unicode */ + char target_name[0]; /* Must be unicode */ }; struct smb_com_transaction2_sfi_req { diff -Nru a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h --- a/fs/cifs/cifsproto.h Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/cifsproto.h Wed Apr 21 00:30:29 2004 @@ -30,8 +30,8 @@ ***************************************************************** */ -extern struct smb_hdr *buf_get(void); -extern void buf_release(void *); +extern struct smb_hdr *cifs_buf_get(void); +extern void cifs_buf_release(void *); extern int smb_send(struct socket *, struct smb_hdr *, unsigned int /* length */ , struct sockaddr *); extern unsigned int _GetXid(void); @@ -41,7 +41,6 @@ extern char *build_path_from_dentry(struct dentry *); extern char *build_wildcard_path_from_dentry(struct dentry *direntry); extern void renew_parental_timestamps(struct dentry *direntry); -extern void *kcalloc(size_t mem, int type); extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, struct smb_hdr * /* input */ , struct smb_hdr * /* out */ , @@ -61,12 +60,6 @@ void DeleteOplockQEntry(struct oplock_q_entry *); extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); extern u64 cifs_UnixTimeToNT(struct timespec); -extern void RevUcode_to_Ucode(char *revUnicode, char *UnicodeName); -extern void Ucode_to_RevUcode(char *Unicode, char *revUnicodeName); -extern void RevUcode_to_Ucode_with_Len(char *revUnicode, char *UnicodeName, - int Len); -extern void Ucode_to_RevUcode_with_Len(char *Unicode, char *revUnicodeName, - int Len); extern int cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, FILE_ALL_INFO * pfile_info, @@ -75,21 +68,9 @@ 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, +extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info); extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses); -extern int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *ntlm_session_key, const struct nls_table *); -extern int CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *SecurityBlob,int SecurityBlobLength, - const struct nls_table *); -extern int CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, - struct cifsSesInfo *ses, int *ntlmv2_flag, - const struct nls_table *); -extern int CIFSNTLMSSPAuthSessSetup(unsigned int xid, - struct cifsSesInfo *ses, char *ntlm_session_key, - int ntlmv2_flag, const struct nls_table *); extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, const char *tree, struct cifsTconInfo *tcon, @@ -224,7 +205,6 @@ extern struct cifsTconInfo *tconInfoAlloc(void); extern void tconInfoFree(struct cifsTconInfo *); -extern int cifs_demultiplex_thread(struct TCP_Server_Info *); extern int cifs_reconnect(struct TCP_Server_Info *server); extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *); diff -Nru a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c --- a/fs/cifs/cifssmb.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/cifssmb.c Wed Apr 21 00:30:29 2004 @@ -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,38 +41,108 @@ int index; char *name; } protocols[] = { - { - CIFS_PROT, "\2NT LM 0.12"}, { - BAD_PROT, "\2"} + {CIFS_PROT, "\2NT LM 0.12"}, + {BAD_PROT, "\2"} }; -int + +/* Mark as invalid, all open files on tree connections since they + were closed when session to server was lost */ +static 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); + /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */ +} + +static int smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, void **request_buf /* returned */ , void **response_buf /* returned */ ) { 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) { + rc = cifs_setup_session(0, tcon->ses, nls_codepage); + 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) return rc; - *request_buf = buf_get(); + *request_buf = cifs_buf_get(); if (request_buf == 0) { return -ENOMEM; } @@ -98,7 +172,6 @@ rc = -EIO; return rc; } - rc = smb_init(SMB_COM_NEGOTIATE, 0, 0 /* no tcon yet */ , (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -120,11 +193,11 @@ if (rc == 0) { server->secMode = pSMBr->SecurityMode; server->secType = NTLM; /* BB override default for NTLMv2 or krb*/ - /* one byte - no need to convert this or EncryptionKeyLen from le,*/ + /* one byte - no need to convert this or EncryptionKeyLen from le,*/ server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); /* probably no need to store and check maxvcs */ server->maxBuf = - min(le32_to_cpu(pSMBr->MaxBufferSize), + min(le32_to_cpu(pSMBr->MaxBufferSize), (__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE); server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); cFYI(0, ("Max buf = %d ", ses->server->maxBuf)); @@ -172,7 +245,6 @@ pSMBr->ByteCount - 16, &server->secType); } - } else server->capabilities &= ~CAP_EXTENDED_SECURITY; if(sign_CIFS_PDUs == FALSE) { @@ -187,7 +259,7 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); return 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); @@ -237,8 +316,14 @@ cFYI(1, (" Tree disconnect failed %d", rc)); if (smb_buffer) - buf_release(smb_buffer); + cifs_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; @@ -266,8 +350,8 @@ rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, 0 /* no tcon anymore */, (void **) &pSMB, (void **) &smb_buffer_response); - if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; if (rc) { up(&ses->sesSem); @@ -285,8 +369,14 @@ ses->server->tcpStatus = CifsExiting; } if (pSMB) - buf_release(pSMB); + cifs_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) @@ -329,7 +420,10 @@ cFYI(1, ("Error in RMFile = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_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) @@ -372,7 +466,9 @@ cFYI(1, ("Error in RMDir = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_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) @@ -415,8 +511,9 @@ cFYI(1, ("Error in Mkdir = %d", rc)); } if (pSMB) - buf_release(pSMB); - + cifs_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) @@ -464,8 +562,14 @@ } pSMB->DesiredAccess = cpu_to_le32(access_flags); pSMB->AllocationSize = 0; - pSMB->FileAttributes = ATTR_NORMAL; /* XP does not handle ATTR_POSIX_SEMANTICS */ - /*if ((omode & S_IWUGO) == 0) + pSMB->FileAttributes = ATTR_NORMAL; + /* XP does not handle ATTR_POSIX_SEMANTICS */ + /* but it helps speed up case sensitive checks for other + servers such as Samba */ + if (tcon->ses->capabilities & CAP_UNIX) + pSMB->FileAttributes |= ATTR_POSIX_SEMANTICS; + + /* if ((omode & S_IWUGO) == 0) pSMB->FileAttributes |= ATTR_READONLY;*/ /* Above line causes problems due to vfs splitting create into two pieces - need to set mode after file created not while it is @@ -501,8 +605,9 @@ } } if (pSMB) - buf_release(pSMB); - + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto openRetry; return rc; } @@ -527,9 +632,9 @@ if (rc) return rc; - /* tcon and ses pointer are checked in smb_init */ - if (tcon->ses->server == NULL) - return -ECONNABORTED; + /* tcon and ses pointer are checked in smb_init */ + if (tcon->ses->server == NULL) + return -ECONNABORTED; pSMB->AndXCommand = 0xFF; /* none */ pSMB->Fid = netfid; @@ -567,10 +672,13 @@ } if (pSMB) { if(*buf) - buf_release(pSMB); + cifs_buf_release(pSMB); 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; } @@ -623,7 +731,10 @@ *nbytes = le16_to_cpu(pSMBr->Count); if (pSMB) - buf_release(pSMB); + cifs_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 +750,9 @@ LOCK_RSP *pSMBr = NULL; int bytes_returned; int timeout = 0; + __u64 temp; - cFYI(1, ("In CIFSSMBLock")); - + cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock)); rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -649,6 +760,12 @@ if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) { timeout = -1; /* no response expected */ + pSMB->Timeout = 0; + } else if (waitFlag == TRUE) { + timeout = 3; /* blocking operation, no timeout */ + pSMB->Timeout = -1; /* blocking - do not time out */ + } else { + pSMB->Timeout = 0; } pSMB->NumberOfLocks = cpu_to_le32(numLock); @@ -658,8 +775,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); @@ -671,8 +792,10 @@ cERROR(1, ("Send error in Lock = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_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 +808,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; @@ -699,7 +825,11 @@ cERROR(1, ("Send error in Close = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + /* Since session is dead, file will be closed on server already */ + if(rc == -EAGAIN) + rc = 0; return rc; } @@ -716,7 +846,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) @@ -766,7 +896,10 @@ cFYI(1, ("Send error in rename = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto renameRetry; return rc; } @@ -774,44 +907,43 @@ 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")); + cFYI(1, ("Rename to File by handle")); + rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; - rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, - (void **) &pSMBr); - if (rc) - return rc; - - pSMB->ParameterCount = 6; - pSMB->MaxSetupCount = 0; - pSMB->Reserved = 0; - pSMB->Flags = 0; - pSMB->Timeout = 0; - pSMB->Reserved2 = 0; - pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req, - Fid) - 4; - pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; + pSMB->ParameterCount = 6; + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req, + Fid) - 4; + pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; - data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; + data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; rename_info = (struct set_file_rename *) data_offset; - pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ - pSMB->SetupCount = 1; - pSMB->Reserved3 = 0; - pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); - pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount; - pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); - pSMB->TotalParameterCount = pSMB->ParameterCount; - pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); - pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); + pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount; + pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); + pSMB->TotalParameterCount = pSMB->ParameterCount; + pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); + pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* construct random name ".cifs_tmp" */ rename_info->overwrite = cpu_to_le32(1); rename_info->root_fid = 0; @@ -836,11 +968,15 @@ rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { - cFYI(1,("Send error in Rename (by file handle) = %d", rc)); + cFYI(1,("Send error in Rename (by file handle) = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_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 +995,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) @@ -929,7 +1065,11 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto createSymLinkRetry; + return rc; } @@ -947,7 +1087,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) @@ -1014,7 +1154,10 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto createHardLinkRetry; + return rc; } @@ -1030,6 +1173,7 @@ int name_len, name_len2; cFYI(1, ("In CIFSCreateHardLink")); +winCreateHardLinkRetry: rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB, (void **) &pSMBr); @@ -1081,7 +1225,9 @@ cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto winCreateHardLinkRetry; return rc; } @@ -1100,6 +1246,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) @@ -1174,7 +1322,9 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto querySymLinkRetry; return rc; } @@ -1256,7 +1406,11 @@ } } if (pSMB) - buf_release(pSMB); + cifs_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 +1428,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) @@ -1334,7 +1489,10 @@ rc = -ENOMEM; } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto QPathInfoRetry; + return rc; } @@ -1352,6 +1510,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) @@ -1413,7 +1572,10 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto UnixQPathInfoRetry; + return rc; } @@ -1430,6 +1592,7 @@ int name_len; cFYI(1, ("In FindUnique")); +findUniqueRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1487,7 +1650,10 @@ /* BB fill in */ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto findUniqueRetry; + return rc; } @@ -1507,6 +1673,7 @@ int name_len; cFYI(1, ("In FindFirst")); +findFirstRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1590,7 +1757,11 @@ memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto findFirstRetry; + return rc; } @@ -1608,6 +1779,7 @@ int bytes_returned; cFYI(1, ("In FindNext")); + if(resume_file_name == NULL) { return -EIO; } @@ -1690,7 +1862,11 @@ memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount)); } if (pSMB) - buf_release(pSMB); + cifs_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 +1877,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; @@ -1716,7 +1896,11 @@ cERROR(1, ("Send error in FindClose = %d", rc)); } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + /* Since session is dead, search handle closed on server already */ + if (rc == -EAGAIN) + rc = 0; return rc; } @@ -1743,7 +1927,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) @@ -1874,7 +2058,11 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto getDFSRetry; + return rc; } @@ -1890,7 +2078,7 @@ int bytes_returned = 0; cFYI(1, ("In QFSInfo")); - +QFSInfoRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -1951,7 +2139,11 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSInfoRetry; + return rc; } @@ -1967,6 +2159,7 @@ int bytes_returned = 0; cFYI(1, ("In QFSAttributeInfo")); +QFSAttributeRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2013,7 +2206,11 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSAttributeRetry; + return rc; } @@ -2029,7 +2226,7 @@ int bytes_returned = 0; cFYI(1, ("In QFSDeviceInfo")); - +QFSDeviceRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2078,7 +2275,12 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSDeviceRetry; + + return rc; } @@ -2094,6 +2296,7 @@ int bytes_returned = 0; cFYI(1, ("In QFSUnixInfo")); +QFSUnixRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2140,7 +2343,12 @@ } } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto QFSUnixRetry; + + return rc; } @@ -2162,7 +2370,7 @@ int bytes_returned = 0; cFYI(1, ("In SetEOF")); - +SetEOFRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2232,7 +2440,11 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetEOFRetry; + return rc; } @@ -2248,8 +2460,7 @@ int bytes_returned = 0; __u32 tmp; - cFYI(1, ("SetFileSize (via SetFileInfo)")); - + cFYI(1, ("SetFileSize (via SetFileInfo) %lld",size)); rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2318,7 +2529,11 @@ } if (pSMB) - buf_release(pSMB); + cifs_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 +2550,7 @@ cFYI(1, ("In SetTimes")); +SetTimesRetry: rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, (void **) &pSMBr); if (rc) @@ -2392,7 +2608,11 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto SetTimesRetry; + return rc; } @@ -2409,7 +2629,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) @@ -2470,6 +2690,8 @@ } if (pSMB) - buf_release(pSMB); + cifs_buf_release(pSMB); + if (rc == -EAGAIN) + goto setPermsRetry; return rc; } diff -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c --- a/fs/cifs/connect.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/connect.c Wed Apr 21 00:30:29 2004 @@ -44,7 +44,7 @@ unsigned char *p24); extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); -extern int inet_addr(char *); +extern int cifs_inet_pton(int, const char *, void *dst); struct smb_vol { char *username; @@ -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; @@ -66,13 +67,14 @@ }; int ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket); +int ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket); /* * cifs tcp session reconnection * * mark tcp session as reconnecting so temporarily locked - * mark all smb sessions as reconnecting for tcp session (TBD BB) + * mark all smb sessions as reconnecting for tcp session * reconnect tcp session * wake up waiters on reconnection? - (not needed currently) */ @@ -84,6 +86,7 @@ struct list_head *tmp; struct cifsSesInfo *ses; struct cifsTconInfo *tcon; + struct mid_q_entry * mid_entry; if(server->tcpStatus == CifsExiting) return rc; @@ -123,13 +126,35 @@ 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); + if(server->protocolType == IPV6) { + rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket); + } else { + rc = ipv4_connect(&server->addr.sockAddr, &server->ssocket); + } if(rc) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(3 * HZ); } else { + atomic_inc(&tcpSesReconnectCount); server->tcpStatus = CifsGood; wake_up(&server->response_q); } @@ -138,7 +163,7 @@ return rc; } -int +static int cifs_demultiplex_thread(struct TCP_Server_Info *server) { int length; @@ -165,7 +190,7 @@ while (server->tcpStatus != CifsExiting) { if (smb_buffer == NULL) - smb_buffer = buf_get(); + smb_buffer = cifs_buf_get(); else memset(smb_buffer, 0, sizeof (struct smb_hdr)); @@ -193,6 +218,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 +227,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; @@ -208,6 +243,8 @@ } pdu_length = 4 + ntohl(smb_buffer->smb_buf_length); + /* Ony read pdu_length after below checks for too short (due + to e.g. int overflow) and too long ie beyond end of buf */ cFYI(1, ("Peek length rcvd: %d with smb length: %d", length, pdu_length)); temp = (char *) smb_buffer; @@ -228,8 +265,8 @@ } else if (temp[0] != (char) 0) { cERROR(1, - ("Unknown RFC 1001 frame received not 0x00 nor 0x85")); - cifs_dump_mem(" Received Data is: ", temp, length); + ("Unknown RFC 1001 frame not 0x00 nor 0x85")); + cifs_dump_mem(" Received Data: ", temp, length); cifs_reconnect(server); csocket = server->ssocket; continue; @@ -257,8 +294,9 @@ length = 0; iov.iov_base = smb_buffer; iov.iov_len = pdu_length; - for (total_read = 0; total_read < pdu_length; total_read += length) { - /* Should improve check for buffer overflow with bad pdu_length */ + for (total_read = 0; + total_read < pdu_length; + total_read += length) { length = sock_recvmsg(csocket, &smb_msg, pdu_length - total_read, 0); if (length == 0) { @@ -286,7 +324,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 +340,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 { @@ -316,14 +355,16 @@ } } } - /* BB add code to lock SMB sessions while releasing */ + + server->tcpStatus = CifsExiting; + 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 */ - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); read_lock(&GlobalSMBSeslock); if (list_empty(&server->pending_mid_q)) { @@ -337,39 +378,85 @@ ses->server = NULL; } } - kfree(server); - } else /* BB need to more gracefully handle the rare negative session - response case because response will be still outstanding */ - cERROR(1, ("Active MIDs in queue while exiting - can not delete mid_q_entries or TCP_Server_Info structure due to pending requests MEMORY LEAK!!")); - /* BB wake up waitors, and/or wait and/or free stale mids and try again? BB */ - /* BB Need to fix bug in error path above - perhaps wait until smb requests - time out and then free the tcp per server struct BB */ - read_unlock(&GlobalSMBSeslock); + read_unlock(&GlobalSMBSeslock); + } else { + 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->midState == MID_REQUEST_SUBMITTED) { + cFYI(1, + (" Clearing Mid 0x%x - waking up ",mid_entry->mid)); + task_to_wake = mid_entry->tsk; + if(task_to_wake) { + wake_up_process(task_to_wake); + } + } + } + spin_unlock(&GlobalMid_Lock); + read_unlock(&GlobalSMBSeslock); + set_current_state(TASK_INTERRUPTIBLE); + /* 1/8th of sec should be more than enough time for them to exit */ + schedule_timeout(HZ/8); + } + + 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 */ + cFYI(1, ("Wait for exit from demultiplex thread")); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(46 * HZ); + /* if threads still have not exited they are probably never + coming home not much else we can do but free the memory */ + } + kfree(server); cFYI(1, ("About to exit from demultiplex thread")); return 0; } -int -parse_mount_options(char *options, const char *devname, struct smb_vol *vol) +static void * +cifs_kcalloc(size_t size, int type) +{ + void *addr; + addr = kmalloc(size, type); + if (addr) + memset(addr, 0, size); + return addr; +} + +static int +cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol) { char *value; char *data; - int temp_len; + int temp_len, i, j; + char separator[2]; + + separator[0] = ','; + separator[1] = 0; - memset(vol,0,sizeof(struct smb_vol)); vol->linux_uid = current->uid; /* current->euid instead? */ vol->linux_gid = current->gid; vol->dir_mode = S_IRWXUGO; /* 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) return 1; - while ((data = strsep(&options, ",")) != NULL) { + if(strncmp(options,"sep=",4) == 0) { + if(options[4] != 0) { + separator[0] = options[4]; + options += 5; + } else { + cFYI(1,("Null separator not allowed")); + } + } + + while ((data = strsep(&options, separator)) != NULL) { if (!*data) continue; if ((value = strchr(data, '=')) != NULL) @@ -389,11 +476,54 @@ } else if (strnicmp(data, "pass", 4) == 0) { if (!value || !*value) { vol->password = NULL; - } else if (strnlen(value, 17) < 17) { - vol->password = value; + continue; + } + temp_len = strlen(value); + /* removed password length check, NTLM passwords + can be arbitrarily long */ + + /* if comma in password, the string will be + prematurely null terminated. Commas in password are + specified across the cifs mount interface by a double + comma ie ,, and a comma used as in other cases ie ',' + as a parameter delimiter/separator is single and due + to the strsep above is temporarily zeroed. */ + + /* NB: password legally can have multiple commas and + the only illegal character in a password is null */ + + if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) { + /* reinsert comma */ + value[temp_len] = separator[0]; + temp_len+=2; /* move after the second comma */ + while(value[temp_len] != 0) { + if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) { + /* single comma indicating start of next parm */ + break; + } + temp_len++; + } + if(value[temp_len] == 0) { + options = NULL; + } else { + value[temp_len] = 0; + /* move options to point to start of next parm */ + options = value + temp_len + 1; + } + /* go from value to (value + temp_len) condensing double commas to singles */ + vol->password = cifs_kcalloc(temp_len, GFP_KERNEL); + for(i=0,j=0;ipassword[j] = value[i]; + if(value[i] == separator[0] && value[i+1] == separator[0]) { + /* skip second comma */ + i++; + } + } + /* value[temp_len] is zeroed above so + vol->password[temp_len] guaranteed to be null */ } else { - printk(KERN_WARNING "CIFS: password too long\n"); - return 1; + vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL); + strcpy(vol->password, value); } } else if (strnicmp(data, "ip", 2) == 0) { if (!value || !*value) { @@ -506,8 +636,29 @@ /* ignore */ } else if (strnicmp(data, "rw", 2) == 0) { vol->rw = TRUE; + } else if ((strnicmp(data, "suid", 4) == 0) || + (strnicmp(data, "nosuid", 6) == 0) || + (strnicmp(data, "exec", 4) == 0) || + (strnicmp(data, "noexec", 6) == 0) || + (strnicmp(data, "nodev", 5) == 0) || + (strnicmp(data, "dev", 3) == 0)) { + /* The mount tool or mount.cifs helper (if present) + uses these opts to set flags, and the flags are read + by the kernel vfs layer before we get here (ie + before read super) so there is no point trying to + parse these options again and set anything and it + is ok to just ignore them */ + continue; } 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); } @@ -537,8 +688,8 @@ return 0; } -struct cifsSesInfo * -find_tcp_session(__u32 new_target_ip_addr, +static struct cifsSesInfo * +cifs_find_tcp_session(__u32 new_target_ip_addr, char *userName, struct TCP_Server_Info **psrvTcp) { struct list_head *tmp; @@ -549,7 +700,7 @@ list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); if (ses->server) { - if (ses->server->sockAddr.sin_addr.s_addr == + if (ses->server->addr.sockAddr.sin_addr.s_addr == new_target_ip_addr) { /* BB lock server and tcp session and increment use count here?? */ *psrvTcp = ses->server; /* found a match on the TCP session */ @@ -568,7 +719,7 @@ return NULL; } -struct cifsTconInfo * +static struct cifsTconInfo * find_unc(__u32 new_target_ip_addr, char *uncName, char *userName) { struct list_head *tmp; @@ -582,9 +733,9 @@ if (tcon->ses->server) { cFYI(1, (" old ip addr: %x == new ip %x ?", - tcon->ses->server->sockAddr.sin_addr. + tcon->ses->server->addr.sockAddr.sin_addr. s_addr, new_target_ip_addr)); - if (tcon->ses->server->sockAddr.sin_addr. + if (tcon->ses->server->addr.sockAddr.sin_addr. s_addr == new_target_ip_addr) { /* BB lock tcon and server and tcp session and increment use count here? */ /* found a match on the TCP session */ @@ -628,7 +779,8 @@ the helper that resolves tcp names, mount to it, try to tcon to it unmount it if fail */ - /* BB free memory for referrals string BB */ + if(referrals) + kfree(referrals); return rc; } @@ -666,95 +818,11 @@ return rc; } -int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info) -{ - int rc = 0; - char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; - 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 */ - rc = CIFSSMBNegotiate(xid, pSesInfo); - pSesInfo->capabilities = pSesInfo->server->capabilities; - pSesInfo->sequence_number = 0; - if (!rc) { - cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", - pSesInfo->server->secMode, - pSesInfo->server->capabilities, - pSesInfo->server->timeZone)); - if (extended_security - && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) - && (pSesInfo->server->secType == NTLMSSP)) { - cFYI(1, ("New style sesssetup ")); - rc = CIFSSpnegoSessSetup(xid, pSesInfo, - NULL /* security blob */, - 0 /* blob length */, - nls_info); - } else if (extended_security - && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) - && (pSesInfo->server->secType == RawNTLMSSP)) { - cFYI(1, ("NTLMSSP sesssetup ")); - rc = CIFSNTLMSSPNegotiateSessSetup(xid, - pSesInfo, - &ntlmv2_flag, - nls_info); - if (!rc) { - if(ntlmv2_flag) { - char * v2_response; - cFYI(1,("Can use more secure NTLM version 2 password hash")); - CalcNTLMv2_partial_mac_key(pSesInfo, - nls_info); - v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); - if(v2_response) { - CalcNTLMv2_response(pSesInfo,v2_response); -/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ - kfree(v2_response); - /* BB Put dummy sig in SessSetup PDU? */ - } else - rc = -ENOMEM; - - } else { - SMBNTencrypt(pSesInfo->password_with_pad, - pSesInfo->server->cryptKey, - ntlm_session_key); - - cifs_calculate_mac_key(pSesInfo->mac_signing_key, - ntlm_session_key, - pSesInfo->password_with_pad); - } - /* for better security the weaker lanman hash not sent - in AuthSessSetup so we no longer calculate it */ - - rc = CIFSNTLMSSPAuthSessSetup(xid, - pSesInfo, - ntlm_session_key, - ntlmv2_flag, - nls_info); - } - } else { /* old style NTLM 0.12 session setup */ - SMBNTencrypt(pSesInfo->password_with_pad, - pSesInfo->server->cryptKey, - ntlm_session_key); - - cifs_calculate_mac_key(pSesInfo->mac_signing_key, - ntlm_session_key, pSesInfo->password_with_pad); - rc = CIFSSessSetup(xid, pSesInfo, - ntlm_session_key, nls_info); - } - if (rc) { - cERROR(1,("Send error in SessSetup = %d",rc)); - } else { - cFYI(1,("CIFS Session Established successfully")); - pSesInfo->status = CifsGood; - } - } - return rc; -} - int ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket) { int rc = 0; + int connected = 0; if(*csocket == NULL) { rc = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket); @@ -769,39 +837,47 @@ } psin_server->sin_family = AF_INET; + if(psin_server->sin_port) { /* user overrode default port */ 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) + connected = 1; + } + + if(!connected) { + /* 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) + connected = 1; + } } - if (rc < 0) { + if (!connected) { psin_server->sin_port = htons(RFC1001_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof (struct sockaddr_in),0); - if (rc < 0) { - cFYI(1, ("Error connecting to socket. %d", rc)); - sock_release(*csocket); - *csocket = NULL; - return rc; - } + if (rc >= 0) + connected = 1; } + /* give up here - unless we want to retry on different + protocol families some day */ + if (!connected) { + cFYI(1,("Error %d connecting to server via ipv4",rc)); + sock_release(*csocket); + *csocket = NULL; + return rc; + } /* 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; return rc; } @@ -810,49 +886,63 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) { int rc = 0; + int connected = 0; - rc = sock_create(PF_INET6, SOCK_STREAM, - IPPROTO_TCP /* IPPROTO_IPV6 ? */ , csocket); - if (rc < 0) { - cERROR(1, ("Error creating socket. Aborting operation")); - return rc; + if(*csocket == NULL) { + rc = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket); + if (rc < 0) { + cERROR(1, ("Error %d creating ipv6 socket",rc)); + *csocket = NULL; + return rc; + } else { + /* BB other socket options to set KEEPALIVE, NODELAY? */ + cFYI(1,("ipv6 Socket created")); + } } psin_server->sin6_family = AF_INET6; + if(psin_server->sin6_port) { /* user overrode default port */ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof (struct sockaddr_in6),0); - if (rc >= 0) { - /* BB other socket options to set KEEPALIVE, timeouts? NODELAY? */ - return rc; - } - } + if (rc >= 0) + connected = 1; + } + + if(!connected) { + /* do not retry on the same port we just failed on */ + if(psin_server->sin6_port != htons(CIFS_PORT)) { + psin_server->sin6_port = htons(CIFS_PORT); - /* do not retry on the same port we just failed on */ - if(psin_server->sin6_port != htons(CIFS_PORT)) { - psin_server->sin6_port = htons(CIFS_PORT); - - rc = (*csocket)->ops->connect(*csocket, - (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in6), 0); -/* BB fix the timeout to be shorter above - and check flags */ + rc = (*csocket)->ops->connect(*csocket, + (struct sockaddr *) psin_server, + sizeof (struct sockaddr_in6),0); + if (rc >= 0) + connected = 1; + } } - if (rc < 0) { + if (!connected) { psin_server->sin6_port = htons(RFC1001_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) - psin_server, - sizeof (struct sockaddr_in6), 0); - if (rc < 0) { - cFYI(1, - ("Error connecting to socket (via ipv6). %d", - rc)); - sock_release(*csocket); - *csocket = NULL; - return rc; - } + psin_server, sizeof (struct sockaddr_in6),0); + if (rc >= 0) + connected = 1; } + /* give up here - unless we want to retry on different + protocol families some day */ + if (!connected) { + cFYI(1,("Error %d connecting to server via ipv6",rc)); + sock_release(*csocket); + *csocket = NULL; + return rc; + } + /* 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 = 7 * HZ; + return rc; } @@ -864,7 +954,7 @@ int xid; struct socket *csocket = NULL; struct sockaddr_in sin_server; -/* struct sockaddr_in6 sin_server6; */ + struct sockaddr_in6 sin_server6; struct smb_vol volume_info; struct cifsSesInfo *pSesInfo = NULL; struct cifsSesInfo *existingCifsSes = NULL; @@ -872,11 +962,16 @@ struct TCP_Server_Info *srvTcp = NULL; xid = GetXid(); - cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); - if (parse_mount_options(mount_data, devname, &volume_info)) { +/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ + + memset(&volume_info,0,sizeof(struct smb_vol)); + + if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { if(volume_info.UNC) kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); FreeXid(xid); return -EINVAL; } @@ -888,17 +983,45 @@ cifserror("No username specified "); /* In userspace mount helper we can get user name from alternate locations such as env variables and files on disk */ + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); FreeXid(xid); return -EINVAL; } - if (volume_info.UNC) { - sin_server.sin_addr.s_addr = inet_addr(volume_info.UNCip); - cFYI(1, ("UNC: %s ", volume_info.UNC)); - } else { - /* BB we could connect to the DFS root? but which server do we ask? */ + if (volume_info.UNCip && volume_info.UNC) { + rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr); + + if(rc == 0) { + /* not ipv4 address, try ipv6 */ + rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); + } + + if(rc != 1) { + /* we failed translating address */ + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); + FreeXid(xid); + return -EINVAL; + } + + cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); + /* success */ + rc = 0; + } else if (volume_info.UNCip){ + /* BB using ip addr as server name connect to the DFS root below */ + cERROR(1,("Connecting to DFS root not implemented yet")); + } else /* which servers DFS root would we conect to */ { cERROR(1, ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); FreeXid(xid); return -EINVAL; } @@ -911,19 +1034,25 @@ cifs_sb->local_nls = load_nls(volume_info.iocharset); if(cifs_sb->local_nls == NULL) { cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); + if(volume_info.UNC) + kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); FreeXid(xid); return -ELIBACC; } } existingCifsSes = - find_tcp_session(sin_server.sin_addr.s_addr, + cifs_find_tcp_session(sin_server.sin_addr.s_addr, volume_info.username, &srvTcp); if (srvTcp) { cFYI(1, ("Existing tcp session with server found ")); } else { /* create socket */ if(volume_info.port) sin_server.sin_port = htons(volume_info.port); + else + sin_server.sin_port = 0; rc = ipv4_connect(&sin_server, &csocket); if (rc < 0) { cERROR(1, @@ -932,6 +1061,8 @@ sock_release(csocket); if(volume_info.UNC) kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); FreeXid(xid); return rc; } @@ -942,16 +1073,20 @@ sock_release(csocket); if(volume_info.UNC) kfree(volume_info.UNC); + if(volume_info.password) + kfree(volume_info.password); FreeXid(xid); return rc; } else { memset(srvTcp, 0, sizeof (struct TCP_Server_Info)); - memcpy(&srvTcp->sockAddr, &sin_server, sizeof (struct sockaddr_in)); + memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in)); /* BB Add code for ipv6 case too */ srvTcp->ssocket = csocket; + srvTcp->protocolType = IPV4; 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); } @@ -960,6 +1095,8 @@ if (existingCifsSes) { pSesInfo = existingCifsSes; cFYI(1, ("Existing smb sess found ")); + if(volume_info.password) + kfree(volume_info.password); } else if (!rc) { cFYI(1, ("Existing smb sess not found ")); pSesInfo = sesInfoAlloc(); @@ -973,8 +1110,7 @@ if (!rc){ if (volume_info.password) - strncpy(pSesInfo->password_with_pad, - volume_info.password,CIFS_ENCPWD_SIZE); + pSesInfo->password = volume_info.password; if (volume_info.username) strncpy(pSesInfo->userName, volume_info.username,MAX_USERNAME_SIZE); @@ -982,11 +1118,14 @@ strncpy(pSesInfo->domainName, volume_info.domainname,MAX_USERNAME_SIZE); pSesInfo->linux_uid = volume_info.linux_uid; - - rc = setup_session(xid,pSesInfo, cifs_sb->local_nls); + down(&pSesInfo->sesSem); + rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); + up(&pSesInfo->sesSem); if(!rc) atomic_inc(&srvTcp->socketUseCount); - } + } else + if(volume_info.password) + kfree(volume_info.password); } /* search for existing tcon to this server share */ @@ -1013,6 +1152,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 +1183,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 +1210,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 @@ -1091,7 +1235,7 @@ return rc; } -int +static int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, char session_key[CIFS_SESSION_KEY_SIZE], const struct nls_table *nls_codepage) @@ -1110,7 +1254,7 @@ cFYI(1, ("In sesssetup ")); - smb_buffer = buf_get(); + smb_buffer = cifs_buf_get(); if (smb_buffer == 0) { return -ENOMEM; } @@ -1162,9 +1306,10 @@ } if(user == NULL) bytes_returned = 0; /* skill null user */ - else - bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); + else + bytes_returned = + cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, + nls_codepage); bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */ bcc_ptr += 2; /* trailing null */ if (domain == NULL) @@ -1257,7 +1402,7 @@ /* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ - ses->serverOS = kcalloc(2 * (len + 1), GFP_KERNEL); + ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *)bcc_ptr, len,nls_codepage); bcc_ptr += 2 * (len + 1); @@ -1268,7 +1413,7 @@ len = UniStrnlen((wchar_t *)bcc_ptr, remaining_words - 1); - ses->serverNOS =kcalloc(2 * (len + 1),GFP_KERNEL); + ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverNOS, (wchar_t *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); @@ -1279,7 +1424,7 @@ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ses->serverDomain = - kcalloc(2*(len+1),GFP_KERNEL); + cifs_kcalloc(2*(len+1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverDomain, (wchar_t *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); @@ -1288,20 +1433,20 @@ } /* else no more room so create dummy domain string */ else ses->serverDomain = - kcalloc(2, + cifs_kcalloc(2, GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ ses->serverDomain = - kcalloc(2, GFP_KERNEL); + cifs_kcalloc(2, GFP_KERNEL); ses->serverNOS = - kcalloc(2, GFP_KERNEL); + cifs_kcalloc(2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - ses->serverOS = kcalloc(len + 1,GFP_KERNEL); + ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; @@ -1309,14 +1454,14 @@ bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverNOS = kcalloc(len + 1,GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverDomain = kcalloc(len + 1,GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; @@ -1341,12 +1486,12 @@ } if (smb_buffer) - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } -int +static int CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, char *SecurityBlob,int SecurityBlobLength, const struct nls_table *nls_codepage) @@ -1365,7 +1510,7 @@ cFYI(1, ("In spnego sesssetup ")); - smb_buffer = buf_get(); + smb_buffer = cifs_buf_get(); if (smb_buffer == 0) { return -ENOMEM; } @@ -1511,7 +1656,7 @@ the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = - kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *) bcc_ptr, len, @@ -1525,7 +1670,7 @@ remaining_words - 1); ses->serverNOS = - kcalloc(2 * (len + 1), + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverNOS, (wchar_t *)bcc_ptr, @@ -1538,7 +1683,7 @@ if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ - ses->serverDomain = kcalloc(2*(len+1),GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverDomain, (wchar_t *)bcc_ptr, len, @@ -1549,10 +1694,10 @@ } /* else no more room so create dummy domain string */ else ses->serverDomain = - kcalloc(2,GFP_KERNEL); + cifs_kcalloc(2,GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ - ses->serverDomain = kcalloc(2, GFP_KERNEL); - ses->serverNOS = kcalloc(2, GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); } } else { /* ASCII */ @@ -1560,7 +1705,7 @@ if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - ses->serverOS = kcalloc(len + 1, GFP_KERNEL); + ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL); strncpy(ses->serverOS, bcc_ptr, len); bcc_ptr += len; @@ -1568,14 +1713,14 @@ bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverNOS = kcalloc(len + 1,GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverDomain = kcalloc(len + 1, GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; @@ -1600,12 +1745,12 @@ } if (smb_buffer) - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } -int +static int CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, struct cifsSesInfo *ses, int * pNTLMv2_flag, const struct nls_table *nls_codepage) @@ -1626,7 +1771,7 @@ cFYI(1, ("In NTLMSSP sesssetup (negotiate) ")); *pNTLMv2_flag = FALSE; - smb_buffer = buf_get(); + smb_buffer = cifs_buf_get(); if (smb_buffer == 0) { return -ENOMEM; } @@ -1822,7 +1967,7 @@ the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = - kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *) bcc_ptr, len, @@ -1837,7 +1982,7 @@ remaining_words - 1); ses->serverNOS = - kcalloc(2 * (len + 1), + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, @@ -1854,7 +1999,7 @@ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ses->serverDomain = - kcalloc(2 * + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); @@ -1880,13 +2025,13 @@ } /* else no more room so create dummy domain string */ else ses->serverDomain = - kcalloc(2, + cifs_kcalloc(2, GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ ses->serverDomain = - kcalloc(2, GFP_KERNEL); + cifs_kcalloc(2, GFP_KERNEL); ses->serverNOS = - kcalloc(2, GFP_KERNEL); + cifs_kcalloc(2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); @@ -1894,7 +2039,7 @@ pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { ses->serverOS = - kcalloc(len + 1, + cifs_kcalloc(len + 1, GFP_KERNEL); strncpy(ses->serverOS, bcc_ptr, len); @@ -1905,7 +2050,7 @@ len = strnlen(bcc_ptr, 1024); ses->serverNOS = - kcalloc(len + 1, + cifs_kcalloc(len + 1, GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; @@ -1914,7 +2059,7 @@ len = strnlen(bcc_ptr, 1024); ses->serverDomain = - kcalloc(len + 1, + cifs_kcalloc(len + 1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; @@ -1940,12 +2085,12 @@ } if (smb_buffer) - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } -int +static int CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, char *ntlm_session_key, int ntlmv2_flag, const struct nls_table *nls_codepage) @@ -1966,7 +2111,7 @@ cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); - smb_buffer = buf_get(); + smb_buffer = cifs_buf_get(); if (smb_buffer == 0) { return -ENOMEM; } @@ -2215,7 +2360,7 @@ the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ ses->serverOS = - kcalloc(2 * (len + 1), GFP_KERNEL); + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (wchar_t *) bcc_ptr, len, @@ -2230,7 +2375,7 @@ remaining_words - 1); ses->serverNOS = - kcalloc(2 * (len + 1), + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, @@ -2246,7 +2391,7 @@ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string not always null terminated (e.g. for Windows XP & 2000) */ ses->serverDomain = - kcalloc(2 * + cifs_kcalloc(2 * (len + 1), GFP_KERNEL); @@ -2271,17 +2416,17 @@ = 0; } /* else no more room so create dummy domain string */ else - ses->serverDomain = kcalloc(2,GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL); } else { /* no room so create dummy domain and NOS string */ - ses->serverDomain = kcalloc(2, GFP_KERNEL); - ses->serverNOS = kcalloc(2, GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - ses->serverOS = kcalloc(len + 1,GFP_KERNEL); + ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; @@ -2289,14 +2434,14 @@ bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverNOS = kcalloc(len+1,GFP_KERNEL); + ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); - ses->serverDomain = kcalloc(len+1,GFP_KERNEL); + ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; @@ -2321,7 +2466,7 @@ } if (smb_buffer) - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } @@ -2342,7 +2487,7 @@ if (ses == NULL) return -EIO; - smb_buffer = buf_get(); + smb_buffer = cifs_buf_get(); if (smb_buffer == 0) { return -ENOMEM; } @@ -2404,8 +2549,10 @@ if (((long) bcc_ptr + (2 * length)) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { + if(tcon->nativeFileSystem) + kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = - kcalloc(length + 2, GFP_KERNEL); + cifs_kcalloc(length + 2, GFP_KERNEL); cifs_strfromUCS_le(tcon->nativeFileSystem, (wchar_t *) bcc_ptr, length, nls_codepage); @@ -2420,8 +2567,10 @@ if (((long) bcc_ptr + length) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { + if(tcon->nativeFileSystem) + kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = - kcalloc(length + 1, GFP_KERNEL); + cifs_kcalloc(length + 1, GFP_KERNEL); strncpy(tcon->nativeFileSystem, bcc_ptr, length); } @@ -2435,7 +2584,7 @@ } if (smb_buffer) - buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } @@ -2472,7 +2621,7 @@ } else cFYI(1, ("No session or bad tcon")); } - /* BB future check active count of tcon and then free if needed BB */ + cifs_sb->tcon = NULL; if (ses) { set_current_state(TASK_INTERRUPTIBLE); @@ -2484,3 +2633,100 @@ FreeXid(xid); return rc; /* BB check if we should always return zero here */ } + +int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, + struct nls_table * nls_info) +{ + int rc = 0; + char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; + 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 */ { + 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", + pSesInfo->server->secMode, + pSesInfo->server->capabilities, + pSesInfo->server->timeZone)); + if (extended_security + && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) + && (pSesInfo->server->secType == NTLMSSP)) { + cFYI(1, ("New style sesssetup ")); + rc = CIFSSpnegoSessSetup(xid, pSesInfo, + NULL /* security blob */, + 0 /* blob length */, + nls_info); + } else if (extended_security + && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) + && (pSesInfo->server->secType == RawNTLMSSP)) { + cFYI(1, ("NTLMSSP sesssetup ")); + rc = CIFSNTLMSSPNegotiateSessSetup(xid, + pSesInfo, + &ntlmv2_flag, + nls_info); + if (!rc) { + if(ntlmv2_flag) { + char * v2_response; + cFYI(1,("Can use more secure NTLM version 2 password hash")); + CalcNTLMv2_partial_mac_key(pSesInfo, + nls_info); + v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); + if(v2_response) { + CalcNTLMv2_response(pSesInfo,v2_response); +/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ + kfree(v2_response); + /* BB Put dummy sig in SessSetup PDU? */ + } else + rc = -ENOMEM; + + } else { + SMBNTencrypt(pSesInfo->password, + pSesInfo->server->cryptKey, + ntlm_session_key); + + cifs_calculate_mac_key(pSesInfo->mac_signing_key, + ntlm_session_key, + pSesInfo->password); + } + /* for better security the weaker lanman hash not sent + in AuthSessSetup so we no longer calculate it */ + + rc = CIFSNTLMSSPAuthSessSetup(xid, + pSesInfo, + ntlm_session_key, + ntlmv2_flag, + nls_info); + } + } else { /* old style NTLM 0.12 session setup */ + SMBNTencrypt(pSesInfo->password, + pSesInfo->server->cryptKey, + ntlm_session_key); + + cifs_calculate_mac_key(pSesInfo->mac_signing_key, + ntlm_session_key, pSesInfo->password); + rc = CIFSSessSetup(xid, pSesInfo, + ntlm_session_key, nls_info); + } + if (rc) { + cERROR(1,("Send error in SessSetup = %d",rc)); + } else { + cFYI(1,("CIFS Session Established successfully")); + pSesInfo->status = CifsGood; + } + } + return rc; +} + diff -Nru a/fs/cifs/dir.c b/fs/cifs/dir.c --- a/fs/cifs/dir.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/dir.c Wed Apr 21 00:30:29 2004 @@ -125,7 +125,7 @@ int rc = -ENOENT; int xid; int oplock = 0; - int desiredAccess = GENERIC_ALL; + int desiredAccess = GENERIC_READ | GENERIC_WRITE; __u16 fileHandle; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; @@ -147,11 +147,15 @@ cFYI(1,("In create for inode %p dentry->inode %p nd flags = 0x%x for %s",inode, direntry->d_inode, nd->flags,full_path)); if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY) - desiredAccess = GENERIC_READ; + desiredAccess = GENERIC_READ; else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) desiredAccess = GENERIC_WRITE; - else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) - desiredAccess = GENERIC_ALL; + else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) { + /* GENERIC_ALL is too much permission to request */ + /* can cause unnecessary access denied on create */ + /* desiredAccess = GENERIC_ALL; */ + desiredAccess = GENERIC_READ | GENERIC_WRITE; + } if((nd->intent.open.flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) disposition = FILE_CREATE; @@ -220,6 +224,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); @@ -282,19 +287,19 @@ full_path, mode, current->euid, current->egid, device_number, cifs_sb->local_nls); if(!rc) { - rc = cifs_get_inode_info_unix(&newinode, full_path, - inode->i_sb); + rc = cifs_get_inode_info_unix(&newinode, full_path, + inode->i_sb); direntry->d_op = &cifs_dentry_ops; if(rc == 0) d_instantiate(direntry, newinode); } } - if (full_path) - kfree(full_path); - FreeXid(xid); + if (full_path) + kfree(full_path); + FreeXid(xid); - return rc; + return rc; } diff -Nru a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/cifs/fcntl.c Wed Apr 21 00:30:29 2004 @@ -0,0 +1,97 @@ +/* + * fs/cifs/fcntl.c + * + * vfs operations that deal with the file control API + * + * Copyright (C) International Business Machines Corp., 2003,2004 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_unicode.h" +#include "cifs_debug.h" + +int cifs_directory_notify(unsigned long arg, struct file * file) +{ + int xid; + int rc = -EINVAL; + struct cifs_sb_info *cifs_sb; + struct cifsTconInfo *pTcon; + char *full_path = NULL; + + xid = GetXid(); + cifs_sb = CIFS_SB(file->f_dentry->d_sb); + pTcon = cifs_sb->tcon; + full_path = build_path_from_dentry(file->f_dentry); + cFYI(1,("cifs dir notify on file %s",full_path)); + /* CIFSSMBNotify */ + FreeXid(xid); + return rc; +} + + +long cifs_fcntl(int file_desc, unsigned int command, unsigned long arg, + struct file * file) +{ + /* Few few file control functions need to be specially mapped. So far + only: + F_NOTIFY (for directory change notification) + And eventually: + F_GETLEASE + F_SETLEASE + need to be mapped here. The others either already are mapped downstream + or do not need to go to the server (client only sideeffects): + F_DUPFD: + F_GETFD: + F_SETFD: + F_GETFL: + F_SETFL: + F_GETLK: + F_SETLK: + F_SETLKW: + F_GETOWN: + F_SETOWN: + F_GETSIG: + F_SETSIG: + */ + long rc = 0; + + cFYI(1,("cifs_fcntl: command %d with arg %lx",command,arg)); /* BB removeme BB */ + + switch (command) { + case F_NOTIFY: + /* let the local call have a chance to fail first */ + rc = generic_file_fcntl(file_desc,command,arg,file); + if(rc) + return rc; + else { + /* local call succeeded try to do remote notify to + pick up changes from other clients to server file */ + cifs_directory_notify(arg, file); + /* BB add case to long and return rc from above */ + return rc; + } + break; + default: + break; + } + return generic_file_fcntl(file_desc,command,arg,file); +} + diff -Nru a/fs/cifs/file.c b/fs/cifs/file.c --- a/fs/cifs/file.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/file.c Wed Apr 21 00:30:29 2004 @@ -47,7 +47,7 @@ struct list_head * tmp; char *full_path = NULL; int desiredAccess = 0x20197; - int disposition = FILE_OPEN; + int disposition; __u16 netfid; FILE_ALL_INFO * buf = NULL; @@ -57,27 +57,27 @@ pTcon = cifs_sb->tcon; if (file->f_flags & O_CREAT) { - /* search inode for this file and fill in file->private_data = */ - pCifsInode = CIFS_I(file->f_dentry->d_inode); - read_lock(&GlobalSMBSeslock); - list_for_each(tmp, &pCifsInode->openFileList) { - pCifsFile = list_entry(tmp,struct cifsFileInfo, flist); - if((pCifsFile->pfile == NULL)&& (pCifsFile->pid = current->pid)){ - /* set mode ?? */ - pCifsFile->pfile = file; /* needed for writepage */ - file->private_data = pCifsFile; - break; - } - } - read_unlock(&GlobalSMBSeslock); - if(file->private_data != NULL) { - rc = 0; - FreeXid(xid); - return rc; - } else { - if(file->f_flags & O_EXCL) - cERROR(1,("could not find file instance for new file %p ",file)); - } + /* search inode for this file and fill in file->private_data = */ + pCifsInode = CIFS_I(file->f_dentry->d_inode); + read_lock(&GlobalSMBSeslock); + list_for_each(tmp, &pCifsInode->openFileList) { + pCifsFile = list_entry(tmp,struct cifsFileInfo, flist); + if((pCifsFile->pfile == NULL)&& (pCifsFile->pid = current->pid)){ + /* set mode ?? */ + pCifsFile->pfile = file; /* needed for writepage */ + file->private_data = pCifsFile; + break; + } + } + read_unlock(&GlobalSMBSeslock); + if(file->private_data != NULL) { + rc = 0; + FreeXid(xid); + return rc; + } else { + if(file->f_flags & O_EXCL) + cERROR(1,("could not find file instance for new file %p ",file)); + } } full_path = build_path_from_dentry(file->f_dentry); @@ -87,29 +87,45 @@ 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; - -/* BB check other flags carefully to find equivalent NTCreateX flags */ - -/* -#define O_CREAT 0100 -#define O_EXCL 0200 -#define O_NOCTTY 0400 -#define O_TRUNC 01000 -#define O_APPEND 02000 -#define O_NONBLOCK 04000 -#define O_NDELAY O_NONBLOCK -#define O_SYNC 010000 -#define FASYNC 020000 -#define O_DIRECT 040000 -#define O_LARGEFILE 0100000 -#define O_DIRECTORY 0200000 -#define O_NOFOLLOW 0400000 -#define O_ATOMICLOOKUP 01000000 */ - - if (file->f_flags & O_CREAT) - disposition = FILE_OVERWRITE; + else if ((file->f_flags & O_ACCMODE) == O_RDWR) { + /* GENERIC_ALL is too much permission to request */ + /* can cause unnecessary access denied on create */ + /* desiredAccess = GENERIC_ALL; */ + desiredAccess = GENERIC_READ | GENERIC_WRITE; + } + +/********************************************************************* + * open flag mapping table: + * + * POSIX Flag CIFS Disposition + * ---------- ---------------- + * O_CREAT FILE_OPEN_IF + * O_CREAT | O_EXCL FILE_CREATE + * O_CREAT | O_TRUNC FILE_OVERWRITE_IF + * O_TRUNC FILE_OVERWRITE + * none of the above FILE_OPEN + * + * Note that there is not a direct match between disposition + * FILE_SUPERSEDE (ie create whether or not file exists although + * O_CREAT | O_TRUNC is similar but truncates the existing + * file rather than creating a new file as FILE_SUPERSEDE does + * (which uses the attributes / metadata passed in on open call) + *? + *? O_SYNC is a reasonable match to CIFS writethrough flag + *? and the read write flags match reasonably. O_LARGEFILE + *? is irrelevant because largefile support is always used + *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, + * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation + *********************************************************************/ + + if((file->f_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + disposition = FILE_CREATE; + else if((file->f_flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) + disposition = FILE_OVERWRITE_IF; + else if((file->f_flags & O_CREAT) == O_CREAT) + disposition = FILE_OPEN_IF; + else + disposition = FILE_OPEN; if (oplockEnabled) oplock = REQ_OPLOCK; @@ -121,7 +137,7 @@ /* 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); + buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); if(buf==0) { if (full_path) kfree(full_path); @@ -134,14 +150,16 @@ cFYI(1, ("cifs_open returned 0x%x ", rc)); cFYI(1, ("oplock: %d ", oplock)); } else { + if(file->private_data) + kfree(file->private_data); file->private_data = - kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); + kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); if (file->private_data) { - memset(file->private_data, 0, - sizeof (struct cifsFileInfo)); + memset(file->private_data, 0, sizeof(struct cifsFileInfo)); 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; @@ -154,8 +172,27 @@ list_add(&pCifsFile->flist,&pCifsInode->openFileList); write_unlock(&GlobalSMBSeslock); write_unlock(&file->f_owner.lock); + if(pCifsInode->clientCanCacheRead) { + /* we have the inode open somewhere else + no need to discard cache data */ + } else { + if(buf) { + /* BB need same check in cifs_create too? */ - if (pTcon->ses->capabilities & CAP_UNIX) + /* if not oplocked, invalidate inode pages if mtime + or file size changed */ + struct timespec temp; + temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime)); + if(timespec_equal(&file->f_dentry->d_inode->i_mtime,&temp) && + (file->f_dentry->d_inode->i_size == (loff_t)le64_to_cpu(buf->EndOfFile))) { + cFYI(1,("inode unchanged on server")); + } else { + cFYI(1,("invalidating remote inode since open detected it changed")); + invalidate_remote_inode(file->f_dentry->d_inode); + } + } + } + if (pTcon->ses->capabilities & CAP_UNIX) rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode, full_path, inode->i_sb); else @@ -200,162 +237,119 @@ /* Try to reaquire byte range locks that were released when session */ /* to server was lost */ -int relock_files(struct cifsFileInfo * cifsFile) +static int cifs_relock_file(struct cifsFileInfo * cifsFile) { int rc = 0; -/* list all locks open on this file */ +/* BB list all locks open on this file and relock */ + return rc; } 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; - - /* 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; + 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; - 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(inode == NULL) + return -EBADF; + if (file->private_data) { + pCifsFile = (struct cifsFileInfo *) file->private_data; + } else + return -EBADF; - if (buf) - kfree(buf); - if (full_path) - kfree(full_path); - FreeXid(xid); - return rc; -} + xid = GetXid(); + down(&pCifsFile->fh_sem); + if(pCifsFile->invalidHandle == FALSE) { + up(&pCifsFile->fh_sem); + FreeXid(xid); + return 0; + } -/* 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); - } + + 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) { + /* GENERIC_ALL is too much permission to request */ + /* can cause unnecessary access denied on create */ + /* desiredAccess = GENERIC_ALL; */ + desiredAccess = GENERIC_READ | GENERIC_WRITE; } - /* 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 (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) { + 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); + + 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; } + cifs_relock_file(pCifsFile); } } - write_unlock(&GlobalSMBSeslock); + + if (buf) + kfree(buf); + if (full_path) + kfree(full_path); + FreeXid(xid); return rc; } @@ -437,6 +431,7 @@ __u32 numLock = 0; __u32 numUnlock = 0; __u64 length; + int wait_flag = FALSE; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; length = 1 + pfLock->fl_end - pfLock->fl_start; @@ -454,14 +449,16 @@ cFYI(1, ("Posix ")); if (pfLock->fl_flags & FL_FLOCK) cFYI(1, ("Flock ")); - if (pfLock->fl_flags & FL_SLEEP) + if (pfLock->fl_flags & FL_SLEEP) { cFYI(1, ("Blocking lock ")); + wait_flag = TRUE; + } if (pfLock->fl_flags & FL_ACCESS) - cFYI(1, ("Process suspended by mandatory locking ")); + cFYI(1, ("Process suspended by mandatory locking - not implemented yet ")); if (pfLock->fl_flags & FL_LEASE) - cFYI(1, ("Lease on file ")); - if (pfLock->fl_flags & 0xFFD0) - cFYI(1, ("Unknown lock flags ")); + cFYI(1, ("Lease on file - not implemented yet")); + if (pfLock->fl_flags & (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE))) + cFYI(1, ("Unknown lock flags 0x%x",pfLock->fl_flags)); if (pfLock->fl_type == F_WRLCK) { cFYI(1, ("F_WRLCK ")); @@ -509,7 +506,7 @@ pfLock->fl_type = F_UNLCK; if (rc != 0) cERROR(1, - ("Error unlocking previously locked range %d during test of lock ", + ("Error unlocking previously locked range %d during test of lock ", rc)); rc = 0; @@ -526,7 +523,7 @@ ((struct cifsFileInfo *) file->private_data)-> netfid, length, pfLock->fl_start, numUnlock, numLock, lockType, - 0 /* wait flag */ ); + wait_flag); FreeXid(xid); return rc; } @@ -541,6 +538,7 @@ struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; int xid, long_op; + struct cifsFileInfo * open_file; xid = GetXid(); @@ -555,20 +553,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,10 +588,11 @@ *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; + i_size_write(file->f_dentry->d_inode, *poffset); } mark_inode_dirty_sync(file->f_dentry->d_inode); FreeXid(xid); @@ -605,24 +614,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 +635,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 +684,6 @@ } kunmap(page); - FreeXid(xid); return rc; } @@ -727,23 +727,38 @@ int rc = 0; struct inode *inode = page->mapping->host; loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; - struct cifsFileInfo *open_file; - struct cifs_sb_info *cifs_sb; + /* struct cifsFileInfo *open_file; + struct cifs_sb_info *cifs_sb; */ xid = GetXid(); - + cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to)); if (position > inode->i_size){ - inode->i_size = position; - if (file->private_data == NULL) { + i_size_write(inode, position); + /*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); @@ -769,7 +784,7 @@ return rc; } -static int +/* static int cifs_sync_page(struct page *page) { struct address_space *mapping; @@ -784,17 +799,17 @@ return 0; inode = mapping->host; if (!inode) - return 0; + return 0;*/ /* fill in rpages then result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */ - cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index)); +/* cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index)); if (rc < 0) return rc; return 0; -} +} */ /* * As file closes, flush all cached write data for this inode checking @@ -837,6 +852,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 +862,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 +887,9 @@ FreeXid(xid); return rc; } - } else + } else { *poffset += bytes_read; + } } FreeXid(xid); @@ -899,7 +925,6 @@ break; page = list_entry(pages->prev, struct page, lru); - list_del(&page->lru); if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) { @@ -908,24 +933,24 @@ continue; } - page_cache_get(page); target = kmap_atomic(page,KM_USER0); if(PAGE_CACHE_SIZE > bytes_read) { memcpy(target,data,bytes_read); + /* zero the tail end of this partial page */ + memset(target+bytes_read,0,PAGE_CACHE_SIZE-bytes_read); bytes_read = 0; } else { memcpy(target,data,PAGE_CACHE_SIZE); bytes_read -= PAGE_CACHE_SIZE; } + kunmap_atomic(target,KM_USER0); - if (!pagevec_add(plru_pvec, page)) - __pagevec_lru_add(plru_pvec); flush_dcache_page(page); SetPageUptodate(page); - kunmap_atomic(target,KM_USER0); unlock_page(page); - page_cache_release(page); + if (!pagevec_add(plru_pvec, page)) + __pagevec_lru_add(plru_pvec); data += PAGE_CACHE_SIZE; } return; @@ -947,46 +972,78 @@ 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; pagevec_init(&lru_pvec, 0); for(i = 0;iprev, struct page, lru); offset = (loff_t)page->index << PAGE_CACHE_SHIFT; + /* count adjacent pages that we will read into */ + contig_pages = 0; + expected_index = list_entry(page_list->prev,struct page,lru)->index; + list_for_each_entry_reverse(tmp_page,page_list,lru) { + if(tmp_page->index == expected_index) { + contig_pages++; + expected_index++; + } else { + break; + } + } + if(contig_pages + i > num_pages) { + contig_pages = num_pages - i; + } + /* for reads over a certain size could initiate async read ahead */ - cFYI(0,("Read %d pages into cache at offset %ld ", - num_pages-i, (unsigned long) offset)); - - read_size = (num_pages - i) * PAGE_CACHE_SIZE; + read_size = contig_pages * 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); + /* BB need to check return code here */ + if(rc== -EAGAIN) { + if(smb_read_data) { + cifs_buf_release(smb_read_data); + smb_read_data = 0; + } + } + } if ((rc < 0) || (smb_read_data == NULL)) { cFYI(1,("Read error in readpages: %d",rc)); /* clean up remaing pages off list */ - while (!list_empty(page_list) && (i < num_pages)) { - page = list_entry(page_list->prev, - struct page, lru); + page = list_entry(page_list->prev, struct page, lru); list_del(&page->lru); + page_cache_release(page); } break; } else if (bytes_read > 0) { @@ -994,24 +1051,37 @@ cifs_copy_cache_pages(mapping, page_list, bytes_read, smb_read_data + 4 /* RFC1000 hdr */ + le16_to_cpu(pSMBr->DataOffset), &lru_pvec); + i += bytes_read >> PAGE_CACHE_SHIFT; - if((bytes_read & PAGE_CACHE_MASK) != bytes_read) { + + if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { cFYI(1,("Partial page %d of %d read to cache",i++,num_pages)); - break; + + i++; /* account for partial page */ + + /* server copy of file can have smaller size than client */ + /* BB do we need to verify this common case ? this case is ok - + if we are at server EOF we will hit it on next read */ + + /* while(!list_empty(page_list) && (i < num_pages)) { + page = list_entry(page_list->prev,struct page, list); + list_del(&page->list); + page_cache_release(page); + } + break; */ } } else { - cFYI(1,("No bytes read cleaning remaining pages off readahead list")); + cFYI(1,("No bytes read (%d) at offset %lld . Cleaning remaining pages from readahead list",bytes_read,offset)); /* BB turn off caching and do new lookup on file size at server? */ while (!list_empty(page_list) && (i < num_pages)) { - page = list_entry(page_list->prev, - struct page, lru); + page = list_entry(page_list->prev, struct page, lru); list_del(&page->lru); + page_cache_release(page); /* BB removeme - replace with zero of page? */ } - break; } if(smb_read_data) { - buf_release(smb_read_data); + cifs_buf_release(smb_read_data); smb_read_data = 0; } bytes_read = 0; @@ -1019,6 +1089,12 @@ pagevec_lru_add(&lru_pvec); +/* need to free smb_read_data buf before exit */ + if(smb_read_data) { + cifs_buf_release(smb_read_data); + smb_read_data = 0; + } + FreeXid(xid); return rc; } @@ -1122,7 +1198,7 @@ }/* could add code here - to validate if device or weird share type? */ /* can not fill in nlink here as in qpathinfo version and Unx search */ - tmp_inode->i_size = pfindData->EndOfFile; + i_size_write(tmp_inode,pfindData->EndOfFile); tmp_inode->i_blocks = (tmp_inode->i_blksize - 1 + pfindData->AllocationSize) >> tmp_inode->i_blkbits; if (pfindData->AllocationSize < pfindData->EndOfFile) @@ -1196,7 +1272,7 @@ pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes); pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); - tmp_inode->i_size = pfindData->EndOfFile; + i_size_write(tmp_inode,pfindData->EndOfFile); tmp_inode->i_blocks = (tmp_inode->i_blksize - 1 + pfindData->NumOfBytes) >> tmp_inode->i_blkbits; @@ -1220,7 +1296,7 @@ } } -void +static void construct_dentry(struct qstr *qstring, struct file *file, struct inode **ptmp_inode, struct dentry **pnew_dentry) { @@ -1244,6 +1320,11 @@ } } else { tmp_dentry = d_alloc(file->f_dentry, qstring); + if(tmp_dentry == NULL) { + cERROR(1,("Failed allocating dentry")); + return; + } + *ptmp_inode = new_inode(file->f_dentry->d_sb); tmp_dentry->d_op = &cifs_dentry_ops; cFYI(0, (" instantiate dentry 0x%p with inode 0x%p ", @@ -1256,13 +1337,44 @@ *pnew_dentry = tmp_dentry; } -void +static void reset_resume_key(struct file * dir_file, + unsigned char * filename, + unsigned int len,int Unicode,struct nls_table * nls_tab) { + struct cifsFileInfo *cifsFile; + + cifsFile = (struct cifsFileInfo *)dir_file->private_data; + if(cifsFile == NULL) + return; + if(cifsFile->search_resume_name) { + kfree(cifsFile->search_resume_name); + } + + if(Unicode) + len *= 2; + cifsFile->resume_name_length = len; + + cifsFile->search_resume_name = + kmalloc(cifsFile->resume_name_length, GFP_KERNEL); + + if(Unicode) + cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name, + filename, len, nls_tab); + else + memcpy(cifsFile->search_resume_name, filename, + cifsFile->resume_name_length); + cFYI(1,("Reset resume key to: %s with len %d",filename,len)); + 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; @@ -1270,19 +1382,25 @@ 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 */ + 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); @@ -1290,9 +1408,15 @@ 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 */ + cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName)); + } dput(tmp_dentry); + return rc; } int @@ -1378,8 +1502,7 @@ searchHandle = findParms.SearchHandle; if(file->private_data == NULL) file->private_data = - kmalloc(sizeof(struct cifsFileInfo), - GFP_KERNEL); + kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL); if (file->private_data) { memset(file->private_data, 0, sizeof (struct cifsFileInfo)); @@ -1387,6 +1510,7 @@ (struct cifsFileInfo *) file->private_data; cifsFile->netfid = searchHandle; cifsFile->invalidHandle = FALSE; + init_MUTEX(&cifsFile->fh_sem); } else { rc = -ENOMEM; break; @@ -1471,10 +1595,18 @@ 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 */ + reset_resume_key(file, pfindData->FileName,qstring.len, + Unicode, cifs_sb->local_nls); + findParms.EndofSearch = 0; + break; + } file->f_pos++; } } else { /* UnixSearch */ @@ -1501,11 +1633,19 @@ 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; + reset_resume_key(file, pfindDataUnix->FileName, + qstring.len,Unicode,cifs_sb->local_nls); + break; + } file->f_pos++; } } @@ -1573,6 +1713,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", @@ -1603,6 +1748,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", @@ -1634,11 +1784,19 @@ || (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; + reset_resume_key(file, pfindData->FileName,qstring.len, + Unicode,cifs_sb->local_nls); + break; + } file->f_pos++; } } else { /* UnixSearch */ @@ -1668,11 +1826,19 @@ || (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; + reset_resume_key(file, pfindDataUnix->FileName,qstring.len, + Unicode,cifs_sb->local_nls); + break; + } file->f_pos++; } } @@ -1696,34 +1862,31 @@ return rc; } +int cifs_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + cFYI(1,("prepare write for page %p from %d to %d",page,from,to)); + if (!PageUptodate(page)) { + if (to - from != PAGE_CACHE_SIZE) { + void *kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr, 0, from); + memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + } + SetPageUptodate(page); + } + return 0; +} -struct address_space_operations cifs_addr_ops = { - .readpage = cifs_readpage, - .readpages = cifs_readpages, - .writepage = cifs_writepage, - .prepare_write = simple_prepare_write, - .commit_write = cifs_commit_write, - .sync_page = cifs_sync_page, - /*.direct_IO = */ -}; - -struct address_space_operations cifs_addr_ops_writethrough = { - .readpage = cifs_readpage, - .readpages = cifs_readpages, - .writepage = cifs_writepage, - .prepare_write = simple_prepare_write, - .commit_write = cifs_commit_write, - .sync_page = cifs_sync_page, - /*.direct_IO = */ -}; -struct address_space_operations cifs_addr_ops_nocache = { +struct address_space_operations cifs_addr_ops = { .readpage = cifs_readpage, .readpages = cifs_readpages, .writepage = cifs_writepage, - .prepare_write = simple_prepare_write, + .prepare_write = simple_prepare_write, /* BB fixme BB */ +/* .prepare_write = cifs_prepare_write, */ /* BB removeme BB */ .commit_write = cifs_commit_write, - .sync_page = cifs_sync_page, + /* .sync_page = cifs_sync_page, */ /*.direct_IO = */ }; - diff -Nru a/fs/cifs/inode.c b/fs/cifs/inode.c --- a/fs/cifs/inode.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/inode.c Wed Apr 21 00:30:29 2004 @@ -125,7 +125,7 @@ inode->i_nlink = le64_to_cpu(findData.Nlinks); findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes); findData.EndOfFile = le64_to_cpu(findData.EndOfFile); - inode->i_size = findData.EndOfFile; + i_size_write(inode,findData.EndOfFile); /* blksize needs to be multiple of two. So safer to default to blksize and blkbits set in superblock so 2**blkbits and blksize will match */ /* inode->i_blksize = @@ -204,10 +204,10 @@ strnlen(search_path, MAX_PATHCONF) + 1, GFP_KERNEL); if (tmp_path == NULL) { - if(buf) - kfree(buf); - FreeXid(xid); - return -ENOMEM; + if(buf) + kfree(buf); + FreeXid(xid); + return -ENOMEM; } strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); @@ -218,10 +218,10 @@ kfree(tmp_path); /* BB fix up inode etc. */ } else if (rc) { - if(buf) - kfree(buf); - FreeXid(xid); - return rc; + if(buf) + kfree(buf); + FreeXid(xid); + return rc; } } else { struct cifsInodeInfo *cifsInfo; @@ -272,10 +272,10 @@ inode->i_mode &= ~(S_IWUGO); /* BB add code here - validate if device or weird share or device type? */ } - inode->i_size = le64_to_cpu(pfindData->EndOfFile); + i_size_write(inode,le64_to_cpu(pfindData->EndOfFile)); pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); inode->i_blocks = - (inode->i_blksize - 1 + pfindData->AllocationSize) >> inode->i_blkbits; + (inode->i_blksize - 1 + pfindData->AllocationSize) >> inode->i_blkbits; inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); @@ -380,8 +380,8 @@ __u16 netfid; rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, - CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, - &netfid, &oplock, NULL, cifs_sb->local_nls); + CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, + &netfid, &oplock, NULL, cifs_sb->local_nls); if(rc==0) { CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls); CIFSSMBClose(xid, pTcon, netfid); @@ -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) @@ -479,7 +480,7 @@ if (!rc) { inode->i_nlink--; - direntry->d_inode->i_size = 0; + i_size_write(direntry->d_inode,0); direntry->d_inode->i_nlink = 0; } @@ -530,17 +531,17 @@ } if((rc == -EIO)||(rc == -EEXIST)) { - int oplock = FALSE; - __u16 netfid; + int oplock = FALSE; + __u16 netfid; - rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, - CREATE_NOT_DIR, - &netfid, &oplock, NULL, cifs_sb_source->local_nls); - if(rc==0) { - CIFSSMBRenameOpenFile(xid,pTcon,netfid, - toName, cifs_sb_source->local_nls); - CIFSSMBClose(xid, pTcon, netfid); - } + rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, + CREATE_NOT_DIR, + &netfid, &oplock, NULL, cifs_sb_source->local_nls); + if(rc==0) { + CIFSSMBRenameOpenFile(xid,pTcon,netfid, + toName, cifs_sb_source->local_nls); + CIFSSMBClose(xid, pTcon, netfid); + } } if (fromName) kfree(fromName); @@ -559,6 +560,21 @@ char *full_path; struct cifs_sb_info *cifs_sb; struct cifsInodeInfo *cifsInode; + loff_t local_size; + struct timespec local_mtime; + int invalidate_inode = FALSE; + + if(direntry->d_inode == NULL) + return -ENOENT; + + cifsInode = CIFS_I(direntry->d_inode); + + if(cifsInode == NULL) + return -ENOENT; + + /* no sense revalidating inode info on file that no one can write */ + if(CIFS_I(direntry->d_inode)->clientCanCacheRead) + return rc; xid = GetXid(); @@ -566,16 +582,14 @@ full_path = build_path_from_dentry(direntry); cFYI(1, - ("Revalidate full path: %s for inode 0x%p with count %d dentry: 0x%p d_time %ld at time %ld ", + ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld", full_path, direntry->d_inode, direntry->d_inode->i_count.counter, direntry, direntry->d_time, jiffies)); - - cifsInode = CIFS_I(direntry->d_inode); - /* BB add check - do not need to revalidate oplocked files */ - - if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) { + if (cifsInode->time == 0){ + /* was set to zero previously to force revalidate */ + } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) { if((S_ISREG(direntry->d_inode->i_mode) == 0) || (direntry->d_inode->i_nlink == 1)) { if (full_path) @@ -586,6 +600,10 @@ cFYI(1,("Have to revalidate file due to hardlinks")); } } + + /* save mtime and size */ + local_mtime = direntry->d_inode->i_mtime; + local_size = direntry->d_inode->i_size; if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path, @@ -606,8 +624,43 @@ } /* should we remap certain errors, access denied?, to zero */ - /* BB if not oplocked, invalidate inode pages if mtime has changed */ + /* if not oplocked, we invalidate inode pages if mtime + or file size had changed on server */ + + if(timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && + (local_size == direntry->d_inode->i_size)) { + cFYI(1,("cifs_revalidate - inode unchanged")); + } else { + /* file may have changed on server */ + if(cifsInode->clientCanCacheRead) { + /* no need to invalidate inode pages since we were + the only ones who could have modified the file and + the server copy is staler than ours */ + } else { + invalidate_inode = TRUE; + } + } + + /* need to write out dirty pages here */ + down(&direntry->d_inode->i_sem); + if(direntry->d_inode->i_mapping) { + /* do we need to lock inode until after invalidate completes below? */ + filemap_fdatawrite(direntry->d_inode->i_mapping); + } + if(invalidate_inode) { + filemap_fdatawait(direntry->d_inode->i_mapping); + /* may eventually have to do this for open files too */ + if(list_empty(&(cifsInode->openFileList))) { + /* Has changed on server - flush read ahead pages */ + cFYI(1,("Invalidating read ahead data on closed file")); + invalidate_remote_inode(direntry->d_inode); + } + } + + + up(&direntry->d_inode->i_sem); + if (full_path) kfree(full_path); FreeXid(xid); @@ -623,78 +676,25 @@ return err; } -void -cifs_truncate_file(struct inode *inode) -{ /* BB remove - may not need this function after all BB */ - int xid; +static int cifs_truncate_page(struct address_space *mapping, loff_t from) +{ + pgoff_t index = from >> PAGE_CACHE_SHIFT; + unsigned offset = from & (PAGE_CACHE_SIZE-1); + struct page *page; + char *kaddr; int rc = 0; - struct cifsFileInfo *open_file = NULL; - struct cifs_sb_info *cifs_sb; - struct cifsTconInfo *pTcon; - struct cifsInodeInfo *cifsInode; - struct dentry *dirent; - char *full_path = NULL; - - xid = GetXid(); - cifs_sb = CIFS_SB(inode->i_sb); - pTcon = cifs_sb->tcon; - - if (list_empty(&inode->i_dentry)) { - cERROR(1, - ("Can not get pathname from empty dentry in inode 0x%p ", - inode)); - 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 */ - } - if (full_path) - kfree(full_path); - FreeXid(xid); - return; -} - -static int cifs_trunc_page(struct address_space *mapping, loff_t from) -{ - pgoff_t index = from >> PAGE_CACHE_SHIFT; - unsigned offset = from & (PAGE_CACHE_SIZE-1); - struct page *page; - char *kaddr; - int rc = 0; - - page = grab_cache_page(mapping, index); - if (!page) - return -ENOMEM; - - kaddr = kmap_atomic(page, KM_USER0); - memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); - flush_dcache_page(page); - kunmap_atomic(kaddr, KM_USER0); - set_page_dirty(page); - unlock_page(page); - page_cache_release(page); - return rc; + page = grab_cache_page(mapping, index); + if (!page) + return -ENOMEM; + + kaddr = kmap_atomic(page, KM_USER0); + memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); + flush_dcache_page(page); + kunmap_atomic(kaddr, KM_USER0); + unlock_page(page); + page_cache_release(page); + return rc; } int @@ -705,6 +705,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 +713,7 @@ __u64 uid = 0xFFFFFFFFFFFFFFFFULL; __u64 gid = 0xFFFFFFFFFFFFFFFFULL; struct cifsInodeInfo *cifsInode; + struct list_head * tmp; xid = GetXid(); @@ -726,32 +728,63 @@ /* BB check if we need to refresh inode from server now ? BB */ - cFYI(1, (" Changing attributes 0x%x", attrs->ia_valid)); + /* need to flush data before changing file size on server */ + filemap_fdatawrite(direntry->d_inode->i_mapping); + filemap_fdatawait(direntry->d_inode->i_mapping); 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)); + 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 */ - 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")); + break; /* now that we found one valid file handle no + sense continuing to loop trying others */ + } } } - /* 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(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)); + } + + /* Server is ok setting allocation size implicitly - no need to call: */ + /*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)); */ + cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size); } } if (attrs->ia_valid & ATTR_UID) { @@ -816,6 +849,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); } @@ -831,8 +866,7 @@ void cifs_delete_inode(struct inode *inode) { - /* Note: called without the big kernel filelock - remember spinlocks! */ cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode)); - /* may have to add back in when safe distributed caching of - directories via e.g. FindNotify added */ + /* may have to add back in if and when safe distributed caching of + directories added e.g. via FindNotify */ } diff -Nru a/fs/cifs/link.c b/fs/cifs/link.c --- a/fs/cifs/link.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/link.c Wed Apr 21 00:30:29 2004 @@ -96,6 +96,8 @@ pTcon = cifs_sb->tcon; target_path = kmalloc(PATH_MAX, GFP_KERNEL); if(target_path == NULL) { + if (full_path) + kfree(full_path); FreeXid(xid); return -ENOMEM; } @@ -212,6 +214,8 @@ len = buflen; tmpbuffer = kmalloc(len,GFP_KERNEL); if(tmpbuffer == NULL) { + if (full_path) + kfree(full_path); FreeXid(xid); return -ENOMEM; } @@ -251,10 +255,11 @@ cFYI(1,("num referral: %d",num_referrals)); if(referrals) { cFYI(1,("referral string: %s ",referrals)); - strncpy(tmpbuffer, referrals, len-1); + strncpy(tmpbuffer, referrals, len-1); } } - + if(referrals) + kfree(referrals); kfree(tmp_path); if(referrals) { kfree(referrals); diff -Nru a/fs/cifs/md4.c b/fs/cifs/md4.c --- a/fs/cifs/md4.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/md4.c Wed Apr 21 00:30:29 2004 @@ -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 -Nru a/fs/cifs/misc.c b/fs/cifs/misc.c --- a/fs/cifs/misc.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/misc.c Wed Apr 21 00:30:29 2004 @@ -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; @@ -99,6 +101,8 @@ kfree(buf_to_free->serverDomain); if (buf_to_free->serverNOS) kfree(buf_to_free->serverNOS); + if (buf_to_free->password) + kfree(buf_to_free->password); kfree(buf_to_free); } @@ -139,20 +143,10 @@ kfree(buf_to_free); } -void * -kcalloc(size_t size, int type) -{ - void *addr; - addr = kmalloc(size, type); - if (addr) - memset(addr, 0, size); - return addr; -} - struct smb_hdr * -buf_get(void) +cifs_buf_get(void) { - struct smb_hdr *ret_buf; + struct smb_hdr *ret_buf = 0; /* We could use negotiated size instead of max_msgsize - but it may be more efficient to always alloc same size @@ -171,11 +165,11 @@ } void -buf_release(void *buf_to_free) +cifs_buf_release(void *buf_to_free) { if (buf_to_free == NULL) { - cFYI(1, ("Null buffer passed to buf_release")); + cFYI(1, ("Null buffer passed to cifs_buf_release")); return; } kmem_cache_free(cifs_req_cachep, buf_to_free); @@ -267,7 +261,7 @@ buffer->Uid = ses->Suid; break; } else { - /* BB eventually call setup_session here */ + /* BB eventually call cifs_setup_session here */ cFYI(1,("local UID found but smb sess with this server does not exist")); } } @@ -324,8 +318,8 @@ ("Entering checkSMB with Length: %x, smb_buf_length: %x ", length, ntohl(smb->smb_buf_length))); if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) - || (4 + ntohl(smb->smb_buf_length) > - CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)) { + || (ntohl(smb->smb_buf_length) > + CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4)) { if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { cERROR(1, ("Length less than 2 + sizeof smb_hdr ")); if (((unsigned int)length >= sizeof (struct smb_hdr) - 1) @@ -333,8 +327,8 @@ return 0; /* some error cases do not return wct and bcc */ } - if (4 + ntohl(smb->smb_buf_length) > - CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) + if (ntohl(smb->smb_buf_length) > + CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) cERROR(1, ("smb_buf_length greater than CIFS_MAX_MSGSIZE ... ")); cERROR(1, @@ -369,8 +363,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; @@ -387,8 +395,6 @@ netfile = list_entry(tmp1,struct cifsFileInfo,tlist); if(pSMB->Fid == netfile->netfid) { struct cifsInodeInfo *pCifsInode; - /* BB Add following logic to mark inode for write through - inode->i_data.a_ops = &cifs_addr_ops_writethrough; */ read_unlock(&GlobalSMBSeslock); cFYI(1,("Matching file id, processing oplock break")); pCifsInode = diff -Nru a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c --- a/fs/cifs/netmisc.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/netmisc.c Wed Apr 21 00:30:29 2004 @@ -125,10 +125,10 @@ /* Convert string containing dotted ip address to binary form */ /* returns 0 if invalid address */ -/* BB add address family, change rc to status flag and return *//* also see inet_pton */ -/* To identify v4 vs. v6 - 1) check for colon (v6 only) 2) then call inet_pton to parse for bad address */ +/* BB add address family, change rc to status flag and return union or for ipv6 */ +/* will need parent to call something like inet_pton to convert ipv6 address BB */ int -inet_addr(char *cp) +cifs_inet_pton(int address_family, char *cp,void *dst) { struct in_addr address; int value; @@ -140,6 +140,9 @@ static const int addr_class_max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; + if(address_family != AF_INET) + return -EAFNOSUPPORT; + for (i = 0; i < 4; i++) { bytes[i] = 0; } @@ -166,6 +169,9 @@ return 0; *end++ = value; temp = *++cp; + } else if (temp == ':') { + cFYI(1,("IPv6 addresses not supported for CIFS mounts yet")); + return -1; } else break; } @@ -182,8 +188,8 @@ return 0; address.s_addr = *((int *) bytes) | htonl(value); - return address.s_addr; - + *((int *)dst) = address.s_addr; + return 1; /* success */ } /***************************************************************************** diff -Nru a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c --- a/fs/cifs/smbencrypt.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/smbencrypt.c Wed Apr 21 00:30:29 2004 @@ -23,8 +23,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -extern int DEBUGLEVEL; - #include #include #include @@ -45,9 +43,7 @@ /* following came from the other byteorder.h to avoid include conflicts */ #define CVAL(buf,pos) (((unsigned char *)(buf))[pos]) #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) -#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16)) #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) -#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((__u32)(val))) /*The following definitions come from lib/md4.c */ @@ -96,12 +92,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); } @@ -151,12 +141,17 @@ __u16 wpwd[129]; /* Password cannot be longer than 128 characters */ - len = strlen((char *) passwd); - if (len > 128) - len = 128; - /* Password must be converted to NT unicode */ - _my_mbstowcs(wpwd, passwd, len); - wpwd[len] = 0; /* Ensure string is null terminated */ + if(passwd) { + len = strlen((char *) passwd); + if (len > 128) { + len = 128; + } + /* Password must be converted to NT unicode */ + _my_mbstowcs(wpwd, passwd, len); + } else + len = 0; + + wpwd[len] = 0; /* Ensure string is null terminated */ /* Calculate length in bytes */ len = _my_wcslen(wpwd) * sizeof (__u16); @@ -179,12 +174,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 +183,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 +219,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 +247,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 +260,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 +274,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 +285,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,66 +292,4 @@ 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 -} - -/*********************************************************** - encode a password buffer. The caller gets to figure out - what to put in it. -************************************************************/ -int -encode_pw_buffer(char buffer[516], char *new_pw, int new_pw_length) -{ - get_random_bytes(buffer, sizeof (buffer)); - - memcpy(&buffer[512 - new_pw_length], new_pw, new_pw_length); - - /* - * The length of the new password is in the last 4 bytes of - * the data buffer. - */ - SIVAL(buffer, 512, new_pw_length); - - 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 -Nru a/fs/cifs/transport.c b/fs/cifs/transport.c --- a/fs/cifs/transport.c Wed Apr 21 00:30:29 2004 +++ b/fs/cifs/transport.c Wed Apr 21 00:30:29 2004 @@ -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; } @@ -93,7 +78,7 @@ list_del(&midEntry->qhead); atomic_dec(&midCount); spin_unlock(&GlobalMid_Lock); - buf_release(midEntry->resp_buf); + cifs_buf_release(midEntry->resp_buf); kmem_cache_free(cifs_mid_cachep, midEntry); } @@ -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,23 +211,25 @@ 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)); - + (struct sockaddr *) &(ses->server->addr.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 */ + else if (long_op == 2) /* writes past end of file can take looooong time */ timeout = 300 * HZ; else if (long_op == 1) timeout = 45 * HZ; /* should be greater than servers oplock break timeout (about 43 seconds) */ - else + else if (long_op > 2) { + timeout = MAX_SCHEDULE_TIMEOUT; + } else timeout = 15 * HZ; /* wait for 15 seconds or until woken up due to response arriving or due to last connection to this server being unmounted */ @@ -227,26 +239,39 @@ 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) { + if(ses->server->tcpStatus == CifsExiting) + rc = -EHOSTDOWN; + else { + 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));