From f191401f5906f4d942fac87ebeb4671faf1ba7d6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 18 Aug 2005 09:37:34 -0700 Subject: [CIFS] rmmod cifs can oops if done soon after the last cifs unmount Signed-off-by: Shaggy (shaggy@austin.ibm.com) Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/cifsfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/cifs/cifsfs.c') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8cc23e7d0d5d..7fda0f7d9c00 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -834,8 +834,8 @@ static int cifs_oplock_thread(void * dummyarg) spin_unlock(&GlobalMid_Lock); } } while(!signal_pending(current)); - complete_and_exit (&cifs_oplock_exited, 0); oplockThread = NULL; + complete_and_exit (&cifs_oplock_exited, 0); } static int __init -- cgit v1.2.3 From 8d0d50948b276b46b75b1b5855d3f9fab1e0fd92 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 18 Aug 2005 09:41:43 -0700 Subject: [CIFS] Change Notify support part 1 - add dnotify thread for processing notify responses. Signed-off-by: Asser Ferno Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'fs/cifs/cifsfs.c') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 7fda0f7d9c00..d77abe236a67 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -59,6 +59,8 @@ unsigned int ntlmv2_support = 0; unsigned int sign_CIFS_PDUs = 1; extern struct task_struct * oplockThread; /* remove sparse warning */ struct task_struct * oplockThread = NULL; +extern struct task_struct * dnotifyThread; /* remove sparse warning */ +struct task_struct * dnotifyThread = NULL; unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; module_param(CIFSMaxBufSize, int, 0); MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); @@ -73,6 +75,7 @@ module_param(cifs_max_pending, int, 0); MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); static DECLARE_COMPLETION(cifs_oplock_exited); +static DECLARE_COMPLETION(cifs_dnotify_exited); extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; @@ -838,6 +841,19 @@ static int cifs_oplock_thread(void * dummyarg) complete_and_exit (&cifs_oplock_exited, 0); } +static int cifs_dnotify_thread(void * dummyarg) +{ + daemonize("cifsdnotifyd"); + allow_signal(SIGTERM); + + dnotifyThread = current; + do { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(39*HZ); + } while(!signal_pending(current)); + complete_and_exit (&cifs_dnotify_exited, 0); +} + static int __init init_cifs(void) { @@ -884,10 +900,16 @@ init_cifs(void) if (!rc) { rc = (int)kernel_thread(cifs_oplock_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_VM); - if(rc > 0) - return 0; - else + if(rc > 0) { + rc = (int)kernel_thread(cifs_dnotify_thread, NULL, + CLONE_FS | CLONE_FILES | CLONE_VM); + if(rc > 0) + return 0; + else + cERROR(1,("error %d create dnotify thread", rc)); + } else { cERROR(1,("error %d create oplock thread",rc)); + } } cifs_destroy_request_bufs(); } @@ -916,6 +938,10 @@ exit_cifs(void) send_sig(SIGTERM, oplockThread, 1); wait_for_completion(&cifs_oplock_exited); } + if(dnotifyThread) { + send_sig(SIGTERM, dnotifyThread, 1); + wait_for_completion(&cifs_dnotify_exited); + } } MODULE_AUTHOR("Steve French "); -- cgit v1.2.3 From 16abbecdad3367c76c12537450eba0d86943fe2c Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 30 Aug 2005 13:10:14 -0700 Subject: [CIFS] Add support for suspend cifsd had been preventing software suspend from completing. Signed-off-by: pavel@suse.de Signed-off-by: Steve French lightly modified --- fs/cifs/CHANGES | 3 ++- fs/cifs/cifsfs.c | 4 ++++ fs/cifs/connect.c | 2 ++ 3 files changed, 8 insertions(+), 1 deletions(-) --- fs/cifs/CHANGES | 3 ++- fs/cifs/cifsfs.c | 4 ++++ fs/cifs/connect.c | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'fs/cifs/cifsfs.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 340b4ffb3493..6c73f020ef40 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -2,7 +2,8 @@ Version 1.36 ------------ Add support for mounting to older pre-CIFS servers such as Windows9x and ME. For these older servers, add option for passing netbios name of server in -on mount (servernetbiosname). +on mount (servernetbiosname). Add suspend support for power management, to +avoid cifsd thread preventing software suspend from working. Add mount option for disabling the default behavior of sending byte range lock requests to the server (necessary for certain applications which break with mandatory lock behavior such as Evolution), and also mount option for diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d77abe236a67..43fb2aafa528 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -784,6 +784,8 @@ static int cifs_oplock_thread(void * dummyarg) oplockThread = current; do { + if(try_to_freeze()) + continue; set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1*HZ); @@ -848,6 +850,8 @@ static int cifs_dnotify_thread(void * dummyarg) dnotifyThread = current; do { + if(try_to_freeze()) + continue; set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(39*HZ); } while(!signal_pending(current)); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c75bae1242dc..134195cc4073 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -355,6 +355,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } while (server->tcpStatus != CifsExiting) { + if(try_to_freeze()) + continue; if (bigbuf == NULL) { bigbuf = cifs_buf_get(); if(bigbuf == NULL) { -- cgit v1.2.3 From e30dcf3a1905b4d2154f95db5fdfdf69691b4f0e Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 20 Sep 2005 20:49:16 -0700 Subject: [CIFS] Add support for legacy servers part eight. Write fixes for Windows ME, and do not set ctime unless explicitly requested with atime and/or mtime (it gets thrown away by most servers anyway as there is no way to set this via posix). Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/CHANGES | 2 ++ fs/cifs/cifsfs.c | 2 +- fs/cifs/cifssmb.c | 15 ++++++----- fs/cifs/inode.c | 78 ++++++++++++++++++++++++++++++++++++++----------------- 4 files changed, 66 insertions(+), 31 deletions(-) (limited to 'fs/cifs/cifsfs.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 8b55e56cf1fe..47ae68b51847 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -2,6 +2,8 @@ Version 1.37 ------------ Fix readdir caching when unlink removes file in current search buffer, and this is followed by a rewind search to just before the deleted entry. +Do not attempt to set ctime unless atime and/or mtime change requested +(most servers throw it away anyway). Version 1.36 ------------ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 43fb2aafa528..f738c8b19e3b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -256,7 +256,7 @@ cifs_alloc_inode(struct super_block *sb) cifs_inode->clientCanCacheAll = FALSE; cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ - + cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; INIT_LIST_HEAD(&cifs_inode->openFileList); return &cifs_inode->vfs_inode; } diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 575b2281518d..f72a61df3c68 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1072,7 +1072,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, if (bytes_sent > count) bytes_sent = count; pSMB->DataOffset = - cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); + cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); if(buf) memcpy(pSMB->Data,buf,bytes_sent); else if(ubuf) { @@ -1080,20 +1080,23 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, cifs_buf_release(pSMB); return -EFAULT; } - } else { + } else if (count != 0) { /* No buffer */ cifs_buf_release(pSMB); return -EINVAL; + } /* else setting file size with write of zero bytes */ + if(wct == 14) + byte_count = bytes_sent + 1; /* pad */ + else /* wct == 12 */ { + byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */ } - - byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */ pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); - pSMB->hdr.smb_buf_length += bytes_sent+1; + pSMB->hdr.smb_buf_length += byte_count; if(wct == 14) pSMB->ByteCount = cpu_to_le16(byte_count); - else { /* old style write has byte count 4 bytes earlier */ + else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */ struct smb_com_writex_req * pSMBW = (struct smb_com_writex_req *)pSMB; pSMBW->ByteCount = cpu_to_le16(byte_count); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 6e82e1ae03b4..ca3af4eafcb2 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1030,14 +1030,15 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) /* now that we found one valid file handle no sense continuing to loop trying others, so break here */ - /* if(rc == -EINVAL) { + if(rc == -EINVAL) { int bytes_written; rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size, - &bytes_written, - NULL, NULL, long_op); - } */ + &bytes_written, NULL, + NULL, 1 /* 45 sec */); + cFYI(1,("wrt seteof rc %d",rc)); + } break; } } @@ -1055,14 +1056,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc)); - /* if(rc == -EINVAL) - old_style_set_eof_via_write(xid, pTcon, - full_path, - attrs->ia_size, - cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR);*/ + cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc)); + if(rc == -EINVAL) { + __u16 netfid; + int oplock = FALSE; + + rc = SMBLegacyOpen(xid, pTcon, full_path, + FILE_OPEN, + SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, + CREATE_NOT_DIR, &netfid, &oplock, + NULL, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + if (rc==0) { + int bytes_written; + rc = CIFSSMBWrite(xid, pTcon, + netfid, 0, + attrs->ia_size, + &bytes_written, NULL, + NULL, 1 /* 45 sec */); + cFYI(1,("wrt seteof rc %d",rc)); + CIFSSMBClose(xid, pTcon, netfid); + } + + } } /* Server is ok setting allocation size implicitly - no need @@ -1075,24 +1092,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) rc = vmtruncate(direntry->d_inode, attrs->ia_size); cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size); - } + } else + goto cifs_setattr_exit; } if (attrs->ia_valid & ATTR_UID) { - cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid)); + cFYI(1, ("UID changed to %d", attrs->ia_uid)); uid = attrs->ia_uid; - /* entry->uid = cpu_to_le16(attr->ia_uid); */ } if (attrs->ia_valid & ATTR_GID) { - cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid)); + cFYI(1, ("GID changed to %d", attrs->ia_gid)); gid = attrs->ia_gid; - /* entry->gid = cpu_to_le16(attr->ia_gid); */ } time_buf.Attributes = 0; if (attrs->ia_valid & ATTR_MODE) { - cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); + cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); mode = attrs->ia_mode; - /* entry->mode = cpu_to_le16(attr->ia_mode); */ } if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) @@ -1132,18 +1147,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); } else time_buf.LastWriteTime = 0; - - if (attrs->ia_valid & ATTR_CTIME) { + /* Do not set ctime explicitly unless other time + stamps are changed explicitly (i.e. by utime() + since we would then have a mix of client and + server times */ + + if (set_time && (attrs->ia_valid & ATTR_CTIME)) { set_time = TRUE; - cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */ + /* Although Samba throws this field away + it may be useful to Windows - but we do + not want to set ctime unless some other + timestamp is changing */ + cFYI(1, ("CIFS - CTIME changed ")); time_buf.ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); } else time_buf.ChangeTime = 0; if (set_time || time_buf.Attributes) { - /* BB what if setting one attribute fails (such as size) but - time setting works? */ time_buf.CreationTime = 0; /* do not change */ /* In the future we should experiment - try setting timestamps via Handle (SetFileInfo) instead of by path */ @@ -1182,12 +1203,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) &time_buf, cifs_sb->local_nls); */ } } + /* Even if error on time set, no sense failing the call if + the server would set the time to a reasonable value anyway, + and this check ensures that we are not being called from + sys_utimes in which case we ought to fail the call back to + the user when the server rejects the call */ + if((rc) && (attrs->ia_valid && + (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) + rc = 0; } /* do not need local check to inode_check_ok since the server does that */ if (!rc) rc = inode_setattr(direntry->d_inode, attrs); +cifs_setattr_exit: kfree(full_path); FreeXid(xid); return rc; -- cgit v1.2.3 From 2096243885ee34b78cb57ce835e07c8536a67d2a Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 21 Sep 2005 22:05:57 -0700 Subject: [CIFS] Add support for legacy servers part nine. statfs (df and du) is now functional, and the length check is fixed so readdir does not throw a warning message when windows me messes up the response to FindFirst of an empty dir (with only . and ..). Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/CHANGES | 3 +- fs/cifs/cifsfs.c | 4 +++ fs/cifs/cifspdu.h | 8 +++++ fs/cifs/cifsproto.h | 2 ++ fs/cifs/cifssmb.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++---- fs/cifs/misc.c | 3 +- fs/cifs/netmisc.c | 2 +- 7 files changed, 107 insertions(+), 10 deletions(-) (limited to 'fs/cifs/cifsfs.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 47ae68b51847..661b45906d09 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -3,7 +3,8 @@ Version 1.37 Fix readdir caching when unlink removes file in current search buffer, and this is followed by a rewind search to just before the deleted entry. Do not attempt to set ctime unless atime and/or mtime change requested -(most servers throw it away anyway). +(most servers throw it away anyway). Fix length check of received smbs +to be more accurate. Version 1.36 ------------ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f738c8b19e3b..1f97d39100ee 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -205,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) #endif /* CIFS_EXPERIMENTAL */ rc = CIFSSMBQFSInfo(xid, pTcon, buf); + /* Old Windows servers do not support level 103, retry with level + one if old server failed the previous call */ + if(rc) + rc = SMBOldQFSInfo(xid, pTcon, buf); /* int f_type; __fsid_t f_fsid; diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index cf466595b0d4..3fa37790bea2 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1683,6 +1683,14 @@ typedef struct { __le32 BytesPerSector; } FILE_SYSTEM_INFO; /* size info, level 0x103 */ +typedef struct { + __le32 fsid; + __le32 SectorsPerAllocationUnit; + __le32 TotalAllocationUnits; + __le32 FreeAllocationUnits; + __le16 BytesPerSector; +} FILE_SYSTEM_ALLOC_INFO; + typedef struct { __le16 MajorVersionNumber; __le16 MinorVersionNumber; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 6943f7c6de08..0bace385e97a 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -133,6 +133,8 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, int remap); extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData); +extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, + struct kstatfs *FSData); extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f72a61df3c68..daf717e6b6eb 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3215,6 +3215,92 @@ GetDFSRefExit: return rc; } +/* Query File System Info such as free space to old servers such as Win 9x */ +int +SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) +{ +/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */ + TRANSACTION2_QFSI_REQ *pSMB = NULL; + TRANSACTION2_QFSI_RSP *pSMBr = NULL; + FILE_SYSTEM_ALLOC_INFO *response_data; + int rc = 0; + int bytes_returned = 0; + __u16 params, byte_count; + + cFYI(1, ("OldQFSInfo")); +oldQFSInfoRetry: + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, + (void **) &pSMBr); + if (rc) + return rc; + + params = 2; /* level */ + pSMB->TotalDataCount = 0; + pSMB->MaxParameterCount = cpu_to_le16(2); + pSMB->MaxDataCount = cpu_to_le16(1000); + pSMB->MaxSetupCount = 0; + pSMB->Reserved = 0; + pSMB->Flags = 0; + pSMB->Timeout = 0; + pSMB->Reserved2 = 0; + byte_count = params + 1 /* pad */ ; + pSMB->TotalParameterCount = cpu_to_le16(params); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->ParameterOffset = cpu_to_le16(offsetof( + struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); + pSMB->DataCount = 0; + pSMB->DataOffset = 0; + pSMB->SetupCount = 1; + pSMB->Reserved3 = 0; + pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); + pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION); + pSMB->hdr.smb_buf_length += byte_count; + pSMB->ByteCount = cpu_to_le16(byte_count); + + rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, + (struct smb_hdr *) pSMBr, &bytes_returned, 0); + if (rc) { + cFYI(1, ("Send error in QFSInfo = %d", rc)); + } else { /* decode response */ + rc = validate_t2((struct smb_t2_rsp *)pSMBr); + + if (rc || (pSMBr->ByteCount < 18)) + rc = -EIO; /* bad smb */ + else { + __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + cFYI(1,("qfsinf resp BCC: %d Offset %d", + pSMBr->ByteCount, data_offset)); + + response_data = + (FILE_SYSTEM_ALLOC_INFO *) + (((char *) &pSMBr->hdr.Protocol) + data_offset); + FSData->f_bsize = + le16_to_cpu(response_data->BytesPerSector) * + le32_to_cpu(response_data-> + SectorsPerAllocationUnit); + FSData->f_blocks = + le32_to_cpu(response_data->TotalAllocationUnits); + FSData->f_bfree = FSData->f_bavail = + le32_to_cpu(response_data->FreeAllocationUnits); + cFYI(1, + ("Blocks: %lld Free: %lld Block size %ld", + (unsigned long long)FSData->f_blocks, + (unsigned long long)FSData->f_bfree, + FSData->f_bsize)); + } + } + cifs_buf_release(pSMB); + + if (rc == -EAGAIN) + goto oldQFSInfoRetry; + + return rc; +} + int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) { @@ -3236,7 +3322,7 @@ QFSInfoRetry: params = 2; /* level */ pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le16(2); - pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ + pSMB->MaxDataCount = cpu_to_le16(1000); pSMB->MaxSetupCount = 0; pSMB->Reserved = 0; pSMB->Flags = 0; @@ -3259,17 +3345,14 @@ QFSInfoRetry: rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { - cERROR(1, ("Send error in QFSInfo = %d", rc)); + cFYI(1, ("Send error in QFSInfo = %d", rc)); } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */ + if (rc || (pSMBr->ByteCount < 24)) rc = -EIO; /* bad smb */ else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); - cFYI(1, - ("Decoding qfsinfo response. BCC: %d Offset %d", - pSMBr->ByteCount, data_offset)); response_data = (FILE_SYSTEM_INFO diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index fafbdbfa63a1..26b35b55f31b 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -450,13 +450,12 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) if ((4 + len != smbCalcSize(smb)) || (4 + len != (unsigned int)length)) { - return 0; - } else { cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); cERROR(1, ("bad smb size detected. The Mid=%d", smb->Mid)); return 1; } + return 0; } int is_valid_oplock_break(struct smb_hdr *buf) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 873b812c0f40..32efa32774d2 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -868,7 +868,7 @@ unsigned int smbCalcSize(struct smb_hdr *ptr) { return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + - BCC(ptr)); + 2 /* size of the bcc field itself */ + BCC(ptr)); } /* The following are taken from fs/ntfs/util.c */ -- cgit v1.2.3 From 68058e757573d4e81550e74c5a03a29a29069ce7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 10 Oct 2005 10:34:22 -0700 Subject: [CIFS] Reduce CIFS tcp congestion timeout (it was too long) and backoff ever longer amounts (up to 15 seconds). This improves performance especially when using large wsize. Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/cifs_debug.c | 4 ++-- fs/cifs/cifsfs.c | 16 +++++++++++++--- fs/cifs/transport.c | 13 +++++++------ 3 files changed, 22 insertions(+), 11 deletions(-) (limited to 'fs/cifs/cifsfs.c') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 785239618d89..b7fb064f6548 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -114,7 +114,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, atomic_read(&ses->server->inFlight)); #ifdef CONFIG_CIFS_STATS2 - buf += sprintf(buf, "\tIn Send: %d In MaxReq Wait: %d", + buf += sprintf(buf, " In Send: %d In MaxReq Wait: %d", atomic_read(&ses->server->inSend), atomic_read(&ses->server->num_waiters)); #endif @@ -267,7 +267,7 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, atomic_read(&tcon->num_oplock_brks)); buf += item_length; length += item_length; - item_length = sprintf(buf, "\nReads: %d Bytes %lld", + item_length = sprintf(buf, "\nReads: %d Bytes %lld", atomic_read(&tcon->num_reads), (long long)(tcon->bytes_read)); buf += item_length; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 1f97d39100ee..e3177a031edc 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -405,6 +405,16 @@ static struct quotactl_ops cifs_quotactl_ops = { }; #endif +static void cifs_umount_begin(struct super_block * sblock) +{ + cERROR(1,("kill all tasks now - umount begin not implemented yet")); + +/* BB FIXME - finish BB */ + + return; +} + + static int cifs_remount(struct super_block *sb, int *flags, char *data) { *flags |= MS_NODIRATIME; @@ -422,7 +432,7 @@ struct super_operations cifs_super_ops = { unless later we add lazy close of inodes or unless the kernel forgets to call us with the same number of releases (closes) as opens */ .show_options = cifs_show_options, -/* .umount_begin = cifs_umount_begin, *//* consider adding in the future */ +/* .umount_begin = cifs_umount_begin, */ /* BB finish in the future */ .remount_fs = cifs_remount, }; @@ -790,9 +800,7 @@ static int cifs_oplock_thread(void * dummyarg) do { if(try_to_freeze()) continue; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1*HZ); spin_lock(&GlobalMid_Lock); if(list_empty(&GlobalOplock_Q)) { spin_unlock(&GlobalMid_Lock); @@ -841,6 +849,8 @@ static int cifs_oplock_thread(void * dummyarg) } } else spin_unlock(&GlobalMid_Lock); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); /* yield in case q were corrupt */ } } while(!signal_pending(current)); oplockThread = NULL; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 893a6fef9853..d9b11690746d 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -157,14 +157,14 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, /* smaller timeout here than send2 since smaller size */ /* Although it may not be required, this also is smaller oplock break time */ - if(i > 30) { + if(i > 12) { cERROR(1, - ("sends on sock %p stuck for 15 seconds", + ("sends on sock %p stuck for 7 seconds", ssocket)); rc = -EAGAIN; break; } - msleep(500); + msleep(1 << i); continue; } if (rc < 0) @@ -224,14 +224,14 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, n_vec - first_vec, total_len); if ((rc == -ENOSPC) || (rc == -EAGAIN)) { i++; - if(i > 40) { + if(i >= 14) { cERROR(1, - ("sends on sock %p stuck for 20 seconds", + ("sends on sock %p stuck for 15 seconds", ssocket)); rc = -EAGAIN; break; } - msleep(500); + msleep(1 << i); continue; } if (rc < 0) @@ -249,6 +249,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, continue; } total_len -= rc; + /* the line below resets i */ for (i = first_vec; i < n_vec; i++) { if (iov[i].iov_len) { if (rc > iov[i].iov_len) { -- cgit v1.2.3 From 5e1253b50111220f06ee13bc4e555d89ff39176b Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 10 Oct 2005 14:06:37 -0700 Subject: [CIFS] Correct cifs tcp retry when some data sent before getting EAGAIN. Continue implementation of cifs umount begin to allow force unmounts of cifs mounts. Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 19 +++++++++++++++++-- fs/cifs/transport.c | 3 +++ 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'fs/cifs/cifsfs.c') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index e3177a031edc..fd5eae37f2a8 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -407,9 +407,24 @@ static struct quotactl_ops cifs_quotactl_ops = { static void cifs_umount_begin(struct super_block * sblock) { - cERROR(1,("kill all tasks now - umount begin not implemented yet")); + struct cifs_sb_info *cifs_sb; -/* BB FIXME - finish BB */ + cifs_sb = CIFS_SB(sb); + if(cifs_sb == NULL) + return -EIO; + if(cifs_sb->tcon == NULL) + return -EIO; + down(&tcon->tconSem); + if (atomic_read(&tcon->useCount) == 1) + tcon->tidStatus = CifsExiting; + up(&tcon->tconSem); + + if((cifs->sb->tcon->ses) && (cifs_sb->tcon->ses->server)) + { + cERROR(1,("wake up tasks now - umount begin not complete")); + wake_up_all(&server->request_q); + } +/* BB FIXME - finish add checks for tidStatus BB */ return; } diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index d9b11690746d..d8865fbd876a 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -169,6 +169,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, } if (rc < 0) break; + else + i = 0; /* reset i after each successful send */ iov.iov_base += rc; iov.iov_len -= rc; len -= rc; @@ -263,6 +265,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, } } } + i = 0; /* in case we get ENOSPC on the next send */ } if (rc < 0) { -- cgit v1.2.3 From 9e2e85f82fa280e937ee42152e7cbaff78be01a2 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 10 Oct 2005 14:28:38 -0700 Subject: [CIFS] Fix minor build problem with previous changeset Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'fs/cifs/cifsfs.c') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index fd5eae37f2a8..99e087d3554f 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -408,21 +408,24 @@ static struct quotactl_ops cifs_quotactl_ops = { static void cifs_umount_begin(struct super_block * sblock) { struct cifs_sb_info *cifs_sb; + struct cifsTconInfo * tcon; cifs_sb = CIFS_SB(sb); if(cifs_sb == NULL) - return -EIO; - if(cifs_sb->tcon == NULL) - return -EIO; + return; + + tcon = cifs_sb->tcon; + if(tcon == NULL) + return; down(&tcon->tconSem); if (atomic_read(&tcon->useCount) == 1) tcon->tidStatus = CifsExiting; up(&tcon->tconSem); - if((cifs->sb->tcon->ses) && (cifs_sb->tcon->ses->server)) + if(tcon->ses && tcon->ses->server) { cERROR(1,("wake up tasks now - umount begin not complete")); - wake_up_all(&server->request_q); + wake_up_all(&tcon->ses->server->request_q); } /* BB FIXME - finish add checks for tidStatus BB */ -- cgit v1.2.3 From 34210f33025a3256b9ac3f0a182f02f1879140cb Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 10 Oct 2005 14:31:13 -0700 Subject: [CIFS] Still missing a line from previous fix Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/cifsfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/cifs/cifsfs.c') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 99e087d3554f..3bc9db522600 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -410,7 +410,7 @@ static void cifs_umount_begin(struct super_block * sblock) struct cifs_sb_info *cifs_sb; struct cifsTconInfo * tcon; - cifs_sb = CIFS_SB(sb); + cifs_sb = CIFS_SB(sblock); if(cifs_sb == NULL) return; -- cgit v1.2.3 From 4ca9c190d902caa7efb899a4c7fc8c6e6d926e95 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 10 Oct 2005 19:52:13 -0700 Subject: [CIFS] Fix oops in experimental notify code (when CONFIG_CIFS_EXPERIMENTAL was turned on). Signed-off-by: Steve French --- fs/cifs/CHANGES | 3 ++- fs/cifs/README | 2 ++ fs/cifs/cifsfs.c | 4 ++++ fs/cifs/fcntl.c | 4 ++++ 4 files changed, 12 insertions(+), 1 deletion(-) (limited to 'fs/cifs/cifsfs.c') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 1c249a2abae3..b2a938378bef 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -8,7 +8,8 @@ allowing an SMBs TCP length to be up to a few bytes longer than it should be. wsize and rsize can now be larger than negotiated buffer size if server supports large readx/writex, even when directio mount flag not specified. Write size will in many cases now be 16K instead of 4K which greatly helps -file copy performance on lightly loaded networks. +file copy performance on lightly loaded networks. Fix oops in dnotify +when experimental config flag enabled. Version 1.37 ------------ diff --git a/fs/cifs/README b/fs/cifs/README index 5d9a953888d9..e7a3ce62d71b 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -296,6 +296,8 @@ A partial list of the supported mount options follows: unused. rsize default read size (usually 16K) wsize default write size (usually 16K, 32K is often better over GigE) + maximum wsize currently allowed by CIFS is 57344 (14 4096 byte + pages) rw mount the network share read-write (note that the server may still consider the share read-only) ro mount network share read-only diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 3bc9db522600..d2d16a9c1f05 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -901,6 +901,10 @@ init_cifs(void) INIT_LIST_HEAD(&GlobalSMBSessionList); INIT_LIST_HEAD(&GlobalTreeConnectionList); INIT_LIST_HEAD(&GlobalOplock_Q); +#ifdef CONFIG_CIFS_EXPERIMENTAL + INIT_LIST_HEAD(&GlobalDnotifyReqList); + INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); +#endif /* * Initialize Global counters */ diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index d527e2c76073..a7a47bb36bf3 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c @@ -78,6 +78,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg) __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; __u16 netfid; + + if(experimEnabled == 0) + return 0; + xid = GetXid(); cifs_sb = CIFS_SB(file->f_dentry->d_sb); pTcon = cifs_sb->tcon; -- cgit v1.2.3