Commit 08b27f50 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://cifs.bkbits.net/linux-2.5cifs

into home.transmeta.com:/home/torvalds/v2.5/linux
parents c8a9fb59 cd73e609
......@@ -14,3 +14,9 @@ and others for their work on the Linux smbfs module over the years. Thanks to
the other members of the Storage Network Industry Association CIFS Technical
Workgroup for their work specifying this highly complex protocol and finally
thanks to the Samba team for their technical advice and encouragement.
Patch Contributors
------------------
Zwane Mwaikambo
Andi Kleen
Version 0.58
------------
Changed read and write to go through pagecache. Added additional address space operations.
Memory mapped operations now working.
Version 0.57
------------
Added writepage code for additional memory mapping support. Fixed leak in xids causing
the simultaneous operations counter (/proc/fs/cifs/SimultaneousOps) to increase on
every stat call. Additional formatting cleanup.
Version 0.56
------------
Fix bigendian bug in order of time conversion. Merge 2.5 to 2.4 version. Formatting cleanup.
Version 0.55
------------
Fixes from Zwane Mwaikambo for adding missing return code checking in a few places.
Also included a modified version of his fix to protect global list manipulation of
the smb session and tree connection and mid related global variables.
Version 0.54
------------
Fix problem with captive thread hanging around at unmount time. Adjust to 2.5.42-pre
......
......@@ -31,9 +31,6 @@ i) support for the Linux 2.5 kernel new feature get_xattr and set_xattr
j) finish off the mount helper, mount.cifs - (started)
k) support for memory mapped files only partially works until support for
MS_INVALIDATE implemented. readpage and writepage code not finished (started)
KNOWN BUGS (updated October 8nd, 2002)
====================================
1) symbolic links (Windows reparse points) are recognized but
......@@ -42,6 +39,8 @@ 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) autoreconnection logic is only partially complete.
4) there may be a problem with truncating a memmapped file to smaller than 4k with
the size being reported as exactly 4k.
Misc testing to do
=================
......
......@@ -79,18 +79,20 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
buf += length;
i = 0;
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalSMBSessionList) {
i++;
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
length =
sprintf(buf,
"\n%d) Name: %s Domain: %s HowManyMounts: %d LocalUsersToSameServer: %d\n\t ServerOS: %s ServerNOS: %s Capabilities: 0x%x ",
i, ses->serverName, ses->serverDomain,
atomic_read(&ses->inUse),
atomic_read(&ses->server->socketUseCount),
ses->serverOS, ses->serverNOS, ses->capabilities);
"\n%d) Name: %s Domain: %s HowManyMounts: %d ServerOS: %s ServerNOS: %s Capabilities: 0x%x\n",
i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse),
ses->serverOS, ses->serverNOS, ses->capabilities);
buf += length;
if(ses->server)
buf += sprintf(buf, "\tLocal Users To Same Server: %d ",atomic_read(&ses->server->socketUseCount));
}
read_unlock(&GlobalSMBSeslock);
sprintf(buf, "\n");
buf++;
printk("\nTotal Buffer so far: %s\n", buf_start);
......@@ -99,6 +101,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
buf += length;
i = 0;
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalTreeConnectionList) {
i++;
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
......@@ -122,6 +125,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
tcon->fsDevInfo.DeviceType);
buf += length;
}
read_unlock(&GlobalSMBSeslock);
length = sprintf(buf, "\n");
buf += length;
*eof = 1;
......@@ -156,22 +160,22 @@ int
cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
int length, int *eof, void *data)
{
int item_length;
int item_length;
length =
sprintf(buf,
"Currently Allocated structures\nCIFS Sessions: %d\n",sesInfoAllocCount.counter);
buf += length;
item_length =
sprintf(buf,"Shares (unique mount targets): %d\n",tconInfoAllocCount.counter);
length += item_length;
buf += item_length;
item_length =
sprintf(buf,"Allocated SMB Request and Response Buffers: %d\n",bufAllocCount.counter);
length += item_length;
buf += item_length;
item_length =
sprintf(buf,"Active Operations (MIDs in use): %d\n",midCount.counter);
length += item_length;
buf += length;
item_length =
sprintf(buf,"Shares (unique mount targets): %d\n",tconInfoAllocCount.counter);
length += item_length;
buf += item_length;
item_length =
sprintf(buf,"Allocated SMB Request and Response Buffers: %d\n",bufAllocCount.counter);
length += item_length;
buf += item_length;
item_length =
sprintf(buf,"Active Operations (MIDs in use): %d\n",midCount.counter);
length += item_length;
return length;
}
......@@ -262,10 +266,13 @@ cifs_proc_clean(void)
remove_proc_entry("DebugData", proc_fs_cifs);
remove_proc_entry("cifsFYI", proc_fs_cifs);
remove_proc_entry("TraceSMB", proc_fs_cifs);
remove_proc_entry("MaxSimultaneousOps", proc_fs_cifs);
remove_proc_entry("SimultaneousOps", proc_fs_cifs);
remove_proc_entry("TotalOps", 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("cifs", proc_root_fs);
}
......
......@@ -64,8 +64,10 @@ cifs_read_super(struct super_block *sb, void *data, char *devname, int silent)
struct cifs_sb_info *cifs_sb;
int rc = 0;
sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
cifs_sb = CIFS_SB(sb);
if(cifs_sb == NULL)
return -ENOMEM;
cifs_sb->local_nls = load_nls_default(); /* needed for ASCII cp to Unicode converts */
rc = cifs_mount(sb, cifs_sb, data, devname);
......@@ -97,13 +99,12 @@ cifs_read_super(struct super_block *sb, void *data, char *devname, int silent)
if (inode)
iput(inode);
/* rc = cifs_umount(sb); BB is CIFS unmount routine needed? */
if (rc) {
cERROR(1, ("cifs_umount failed with return code %d\n", rc));
cERROR(1, ("cifs_mount failed with no root inode"));
}
out_mount_failed:
if(cifs_sb)
kfree(cifs_sb);
if(cifs_sb)
kfree(cifs_sb);
return -EINVAL;
}
......@@ -115,14 +116,16 @@ cifs_put_super(struct super_block *sb)
cFYI(1, ("In cifs_put_super\n"));
cifs_sb = CIFS_SB(sb);
rc = cifs_umount(sb, cifs_sb);
if(cifs_sb == NULL) {
cFYI(1,("\nEmpty cifs superblock info passed to unmount"));
return;
}
rc = cifs_umount(sb, cifs_sb);
if (rc) {
cERROR(1, ("cifs_umount failed with return code %d\n", rc));
}
if(cifs_sb) {
unload_nls(cifs_sb->local_nls);
kfree(cifs_sb);
}
unload_nls(cifs_sb->local_nls);
kfree(cifs_sb);
return;
}
......@@ -155,7 +158,7 @@ cifs_statfs(struct super_block *sb, struct statfs *buf)
__fsid_t f_fsid;
int f_namelen; */
/* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */
FreeXid(xid);
return 0; /* always return success? what if volume is no longer available? */
}
......@@ -176,7 +179,7 @@ cifs_alloc_inode(struct super_block *sb)
atomic_set(&cifs_inode->inUse, 0);
cifs_inode->time = 0;
cifs_inode->clientCanCache = 0;
INIT_LIST_HEAD(&cifs_inode->openFileList);
INIT_LIST_HEAD(&cifs_inode->openFileList);
return &cifs_inode->vfs_inode;
}
......@@ -258,6 +261,7 @@ static struct file_system_type cifs_fs_type = {
struct inode_operations cifs_dir_inode_ops = {
.create = cifs_create,
.lookup = cifs_lookup,
.getattr = cifs_getattr,
.unlink = cifs_unlink,
.link = cifs_hardlink,
.mkdir = cifs_mkdir,
......@@ -271,6 +275,7 @@ struct inode_operations cifs_dir_inode_ops = {
struct inode_operations cifs_file_inode_ops = {
/* revalidate:cifs_revalidate, */
.setattr = cifs_setattr,
.getattr = cifs_getattr,
.rename = cifs_rename,
};
......@@ -278,17 +283,18 @@ struct inode_operations cifs_symlink_inode_ops = {
.readlink = cifs_readlink,
.follow_link = cifs_follow_link,
/* BB add the following two eventually */
/* revalidate: cifs_revalidate,
setattr: cifs_notify_change, *//* BB do we need notify change */
/* revalidate: cifs_revalidate,
setattr: cifs_notify_change, *//* BB do we need notify change */
};
struct file_operations cifs_file_ops = {
.read = cifs_read,
.write = cifs_write,
.read = generic_file_read,
.write = generic_file_write,
.open = cifs_open,
.release = cifs_close,
.lock = cifs_lock,
.fsync = cifs_fsync,
.mmap = cifs_file_mmap,
};
struct file_operations cifs_dir_ops = {
......@@ -387,8 +393,11 @@ init_cifs(void)
atomic_set(&tconInfoAllocCount, 0);
atomic_set(&bufAllocCount, 0);
atomic_set(&midCount, 0);
GlobalCurrentXid = 0;
GlobalTotalActiveXid = 0;
GlobalMaxActiveXid = 0;
GlobalSMBSeslock = RW_LOCK_UNLOCKED;
GlobalMid_Lock = RW_LOCK_UNLOCKED;
rc = cifs_init_inodecache();
if (!rc) {
......@@ -419,7 +428,7 @@ exit_cifs(void)
#if CONFIG_PROC_FS
cifs_proc_clean();
#endif
unregister_filesystem(&cifs_fs_type);
unregister_filesystem(&cifs_fs_type);
cifs_destroy_inodecache();
cifs_destroy_mids();
cifs_destroy_request_bufs();
......
......@@ -55,6 +55,7 @@ extern int cifs_rmdir(struct inode *, struct dentry *);
extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
struct dentry *);
extern int cifs_revalidate(struct dentry *);
extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int cifs_setattr(struct dentry *, struct iattr *);
extern struct inode_operations cifs_file_inode_ops;
......@@ -73,7 +74,7 @@ extern ssize_t cifs_write(struct file *file, const char *write_data,
size_t write_size, loff_t * poffset);
extern int cifs_lock(struct file *, int, struct file_lock *);
extern int cifs_fsync(struct file *, struct dentry *, int);
extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
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);
......
......@@ -165,7 +165,7 @@ struct cifsSesInfo {
*/
struct cifsTconInfo {
struct list_head cifsConnectionList;
struct list_head openFileList;
struct list_head openFileList;
struct semaphore tconSem;
struct cifsSesInfo *ses; /* pointer to session associated with */
char treeName[MAX_TREE_SIZE + 1]; /* The ascii or unicode name of this resource depending on the ses->capabilities *//* BB fill in this field */
......@@ -201,6 +201,7 @@ struct cifsFileInfo {
__u16 netfid; /* file id from remote */
/* BB add lock scope info here if needed */ ;
/* lock scope id (0 if none) */
struct file * pfile; /* needed for writepage */
int endOfSearch:1; /* we have reached end of search */
int closePend:1; /* file is marked to close */
};
......@@ -212,12 +213,12 @@ struct cifsFileInfo {
struct cifsInodeInfo {
struct list_head lockList;
/* BB add in lists for dirty pages - i.e. write caching info for oplock */
struct list_head openFileList;
struct list_head openFileList;
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system etc. */
atomic_t inUse; /* num concurrent users (local openers cifs) of file */
unsigned long time; /* jiffies of last update/check of inode */
int clientCanCache:1; /* oplocked. We need to extend cases beyond this i.e. what
if file read-only or if file locked? or if file on r/o vol? */
if file read-only or if file locked? or if file on r/o vol? */
struct inode vfs_inode;
};
......@@ -244,7 +245,7 @@ struct mid_q_entry {
struct cifsSesInfo *ses; /* smb was sent to this server */
struct task_struct *tsk; /* task waiting for response */
struct smb_hdr *resp_buf; /* response buffer */
int midState; /* wish this could be an enum but can not pass that to wait_event */
int midState; /* wish this were enum but can not pass to wait_event */
};
#define MID_FREE 0
......@@ -292,13 +293,10 @@ GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */
*/
GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH];
GLOBAL_EXTERN struct list_head GlobalServerList; /* BB this one is not implemented yet */
GLOBAL_EXTERN struct list_head GlobalServerList; /* BB not implemented yet */
GLOBAL_EXTERN struct list_head GlobalSMBSessionList;
GLOBAL_EXTERN struct list_head GlobalTreeConnectionList;
/*
* Global list of free SMB structures
*/
GLOBAL_EXTERN void *GlobalFreeSMB;
GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
/*
* Global transaction id (XID) information
......@@ -306,7 +304,8 @@ GLOBAL_EXTERN void *GlobalFreeSMB;
GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */
GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */
GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */
GLOBAL_EXTERN rwlock_t GlobalMid_Lock; /* protects above and list operations */
/* on midQ entries */
GLOBAL_EXTERN char Local_System_Name[15];
/*
......@@ -321,13 +320,12 @@ GLOBAL_EXTERN atomic_t midCount;
/* Misc globals */
GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
to be established on existing mount if we
have the uid/password or Kerberos credential
or equivalent for current user */
to be established on existing mount if we
have the uid/password or Kerberos credential
or equivalent for current user */
GLOBAL_EXTERN unsigned int oplockEnabled;
GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
with more secure ntlmssp2 challenge/resp */
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 */
This diff is collapsed.
......@@ -487,7 +487,7 @@ CIFSSMBRead(const int xid, const struct cifsTconInfo *tcon,
(tcon->ses->maxBuf -
MAX_CIFS_HDR_SIZE) & 0xFFFFFF00));
pSMB->MaxCountHigh = 0;
pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
......@@ -497,15 +497,20 @@ CIFSSMBRead(const int xid, const struct cifsTconInfo *tcon,
} else {
pSMBr->DataLength = le16_to_cpu(pSMBr->DataLength);
*nbytes = pSMBr->DataLength;
/* BB check that DataLength would not go beyond end of SMB BB */
if (pSMBr->DataLength > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
/*check that DataLength would not go beyond end of SMB */
if ((pSMBr->DataLength > CIFS_MAX_MSGSIZE)
|| (pSMBr->DataLength > count)) {
rc = -EIO;
*nbytes = 0;
} else {
pReadData =
(char *) (&pSMBr->hdr.Protocol) +
le16_to_cpu(pSMBr->DataOffset);
copy_to_user(buf, pReadData, pSMBr->DataLength);
/* if(rc = copy_to_user(buf, pReadData, pSMBr->DataLength)) {
cERROR(1,("\nFaulting on read rc = %d",rc));
rc = -EFAULT;
}*/ /* can not use copy_to_user when using page cache*/
memcpy(buf,pReadData,pSMBr->DataLength);
}
}
......@@ -544,7 +549,8 @@ CIFSSMBWrite(const int xid, const struct cifsTconInfo *tcon,
pSMB->DataLengthHigh = 0;
pSMB->DataOffset =
cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
copy_from_user(pSMB->Data, buf, pSMB->DataLengthLow);
memcpy(pSMB->Data,buf,pSMB->DataLengthLow);
pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ;
pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow);
......
This diff is collapsed.
This diff is collapsed.
......@@ -52,9 +52,9 @@ cifs_get_inode_info_unix(struct inode **pinode,
if (rc) {
if (rc == -EREMOTE) {
/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path,
&referrals,
&num_referrals,
cifs_sb->local_nls); */
&referrals,
&num_referrals,
cifs_sb->local_nls); */
tmp_path =
kmalloc(strnlen
(pTcon->treeName,
......@@ -99,12 +99,12 @@ cifs_get_inode_info_unix(struct inode **pinode,
atomic_inc(&cifsInfo->inUse); /* inc on every refresh of inode */
inode->i_atime =
le64_to_cpu(cifs_NTtimeToUnix(findData.LastAccessTime));
cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
inode->i_mtime =
le64_to_cpu(cifs_NTtimeToUnix
cifs_NTtimeToUnix(le64_to_cpu
(findData.LastModificationTime));
inode->i_ctime =
le64_to_cpu(cifs_NTtimeToUnix(findData.LastStatusChange));
cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
inode->i_mode = le64_to_cpu(findData.Permissions);
findData.Type = le32_to_cpu(findData.Type);
if (findData.Type == UNIX_FILE) {
......@@ -140,6 +140,7 @@ cifs_get_inode_info_unix(struct inode **pinode,
cFYI(1, (" File inode "));
inode->i_op = &cifs_file_inode_ops;
inode->i_fop = &cifs_file_ops;
inode->i_data.a_ops = &cifs_addr_ops;
} else if (S_ISDIR(inode->i_mode)) {
cFYI(1, (" Directory inode"));
inode->i_op = &cifs_dir_inode_ops;
......@@ -182,9 +183,9 @@ cifs_get_inode_info(struct inode **pinode,
if (rc == -EREMOTE) {
/* BB add call to new func rc = GetDFSReferral(); */
/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path,
&referrals,
&num_referrals,
cifs_sb->local_nls); */
&referrals,
&num_referrals,
cifs_sb->local_nls); */
tmp_path =
kmalloc(strnlen
(pTcon->treeName,
......@@ -265,6 +266,7 @@ cifs_get_inode_info(struct inode **pinode,
cFYI(1, (" File inode "));
inode->i_op = &cifs_file_inode_ops;
inode->i_fop = &cifs_file_ops;
inode->i_data.a_ops = &cifs_addr_ops;
} else if (S_ISDIR(inode->i_mode)) {
cFYI(1, (" Directory inode "));
inode->i_op = &cifs_dir_inode_ops;
......@@ -441,9 +443,11 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
cifs_sb_source = CIFS_SB(source_inode->i_sb);
pTcon = cifs_sb_source->tcon;
if (pTcon != cifs_sb_target->tcon)
if (pTcon != cifs_sb_target->tcon) {
return -EXDEV; /* BB actually could be allowed if same server, but
different share. Might eventually add support for this */
FreeXid(xid);
}
fromName = build_path_from_dentry(source_direntry);
toName = build_path_from_dentry(target_direntry);
......@@ -455,6 +459,7 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
if (toName)
kfree(toName);
FreeXid(xid);
return rc;
}
......@@ -479,7 +484,7 @@ cifs_revalidate(struct dentry *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))
&& (direntry->d_inode->i_nlink == 1)) {
cFYI(1, (" Do not need to revalidate "));
......@@ -505,12 +510,20 @@ cifs_revalidate(struct dentry *direntry)
return rc;
}
int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{
int err = cifs_revalidate(dentry);
if (!err)
generic_fillattr(dentry->d_inode, stat);
return err;
}
void
cifs_truncate_file(struct inode *inode)
{ /* BB remove - may not need this function after all BB */
int xid;
int rc = 0;
struct cifsFileInfo *open_file = NULL;
struct cifsFileInfo *open_file = NULL;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
struct cifsInodeInfo *cifsInode;
......@@ -534,21 +547,19 @@ cifs_truncate_file(struct inode *inode)
full_path = build_path_from_dentry(dirent);
rc = CIFSSMBSetEOF(xid, pTcon, full_path, inode->i_size,FALSE,
cifs_sb->local_nls);
cFYI(1,("\nSetEOF (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 and
also we could also override the smb pid with the pid
of the file opener when sending the CIFS request */
rc = CIFSSMBSetFileSize(xid, pTcon, inode->i_size,
open_file->netfid,open_file->pid,FALSE);
} else {
cFYI(1,("\nNo open files to get file handle from"));
}
}
cFYI(1,("\nSetEOF (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,("\nNo 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 */
......@@ -567,7 +578,7 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
struct cifsTconInfo *pTcon;
char *full_path = NULL;
int rc = -EACCES;
struct cifsFileInfo *open_file = NULL;
struct cifsFileInfo *open_file = NULL;
FILE_BASIC_INFO time_buf;
int set_time = FALSE;
__u64 mode = 0xFFFFFFFFFFFFFFFF;
......@@ -593,19 +604,19 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
if (attrs->ia_valid & ATTR_SIZE) {
rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
cifs_sb->local_nls);
cFYI(1,("\nSetEOF (setattrs) rc = %d",rc));
cFYI(1,("\nSetEOF (setattrs) rc = %d",rc));
if(rc == -ETXTBSY) {
if(!list_empty(&(cifsInode->openFileList))) {
open_file = list_entry(cifsInode->openFileList.next,
struct cifsFileInfo, flist);
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,("\nNo open files to get file handle from"));
}
}
rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
open_file->netfid,open_file->pid,FALSE);
} else {
cFYI(1,("\nNo open files to get file handle from"));
}
}
/* Set Allocation Size of file - might not even need to call the
following but might as well and it does not hurt if it fails */
CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);
......@@ -684,5 +695,4 @@ cifs_delete_inode(struct inode *inode)
cFYI(1, ("In cifs_delete_inode, inode = 0x%p\n", inode));
/* may have to add back in when safe distributed caching of
directories via e.g. FindNotify added */
}
......@@ -22,17 +22,17 @@ struct HMACMD5Context {
void MD5Init(struct MD5Context *context);
void MD5Update(struct MD5Context *context, unsigned char const *buf,
unsigned len);
unsigned len);
void MD5Final(unsigned char digest[16], struct MD5Context *context);
/* The following definitions come from lib/hmacmd5.c */
void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
struct HMACMD5Context *ctx);
struct HMACMD5Context *ctx);
void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
struct HMACMD5Context *ctx);
struct HMACMD5Context *ctx);
void hmac_md5_update(const unsigned char *text, int text_len,
struct HMACMD5Context *ctx);
struct HMACMD5Context *ctx);
void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx);
void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
unsigned char *digest);
unsigned char *digest);
......@@ -28,7 +28,6 @@
extern kmem_cache_t *cifs_req_cachep;
static DECLARE_MUTEX(GlobalMid_Sem); /* also protects XID globals */
__u16 GlobalMid; /* multiplex id - rotating counter */
/* The xid serves as a useful identifier for each incoming vfs request,
......@@ -42,21 +41,21 @@ _GetXid(void)
{
unsigned int xid;
down(&GlobalMid_Sem);
write_lock(&GlobalMid_Lock);
GlobalTotalActiveXid++;
if (GlobalTotalActiveXid > GlobalMaxActiveXid)
GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */
xid = GlobalCurrentXid++;
up(&GlobalMid_Sem);
write_unlock(&GlobalMid_Lock);
return xid;
}
void
_FreeXid(unsigned int xid)
{
down(&GlobalMid_Sem);
write_lock(&GlobalMid_Lock);
GlobalTotalActiveXid--;
up(&GlobalMid_Sem);
write_unlock(&GlobalMid_Lock);
}
struct cifsSesInfo *
......@@ -69,9 +68,11 @@ sesInfoAlloc(void)
GFP_KERNEL);
if (ret_buf) {
memset(ret_buf, 0, sizeof (struct cifsSesInfo));
write_lock(&GlobalSMBSeslock);
atomic_inc(&sesInfoAllocCount);
list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList);
init_MUTEX(&ret_buf->sesSem);
write_unlock(&GlobalSMBSeslock);
}
return ret_buf;
}
......@@ -84,8 +85,10 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
return;
}
write_lock(&GlobalSMBSeslock);
atomic_dec(&sesInfoAllocCount);
list_del(&buf_to_free->cifsSessionList);
write_unlock(&GlobalSMBSeslock);
if (buf_to_free->serverOS)
kfree(buf_to_free->serverOS);
if (buf_to_free->serverDomain)
......@@ -104,11 +107,13 @@ tconInfoAlloc(void)
GFP_KERNEL);
if (ret_buf) {
memset(ret_buf, 0, sizeof (struct cifsTconInfo));
write_lock(&GlobalSMBSeslock);
atomic_inc(&tconInfoAllocCount);
list_add(&ret_buf->cifsConnectionList,
&GlobalTreeConnectionList);
INIT_LIST_HEAD(&ret_buf->openFileList);
INIT_LIST_HEAD(&ret_buf->openFileList);
init_MUTEX(&ret_buf->tconSem);
write_unlock(&GlobalSMBSeslock);
}
return ret_buf;
}
......@@ -120,9 +125,10 @@ tconInfoFree(struct cifsTconInfo *buf_to_free)
cFYI(1, ("\nNull buffer passed to tconInfoFree"));
return;
}
write_lock(&GlobalSMBSeslock);
atomic_dec(&tconInfoAllocCount);
list_del(&buf_to_free->cifsConnectionList);
write_unlock(&GlobalSMBSeslock);
if (buf_to_free->nativeFileSystem)
kfree(buf_to_free->nativeFileSystem);
kfree(buf_to_free);
......@@ -203,9 +209,10 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
buffer->Pid = tmp & 0xFFFF;
tmp >>= 16;
buffer->PidHigh = tmp & 0xFFFF;
down(&GlobalMid_Sem);
write_lock(&GlobalMid_Lock);
GlobalMid++;
buffer->Mid = GlobalMid;
write_unlock(&GlobalMid_Lock);
if (treeCon) {
buffer->Tid = treeCon->tid;
if (treeCon->ses) {
......@@ -218,13 +225,11 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
}
if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
buffer->Flags2 |= SMBFLG2_DFS;
if(treeCon->ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
if(treeCon->ses->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
}
/* endian conversion of flags is now done just before sending */
up(&GlobalMid_Sem);
buffer->WordCount = (char) word_count;
return;
}
......@@ -233,17 +238,18 @@ int
checkSMBhdr(struct smb_hdr *smb, __u16 mid)
{
/* Make sure that this really is an SMB, that it is a response,
and that the message ids match */
if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) && (mid == smb->Mid)) {
if(smb->Flags & SMBFLG_RESPONSE)
return 0;
else {
/* only one valid case where server sends us request */
if(smb->Command == SMB_COM_LOCKING_ANDX)
return 0;
else
cERROR(1, ("\n Rcvd Request not response "));
}
and that the message ids match */
if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
(mid == smb->Mid)) {
if(smb->Flags & SMBFLG_RESPONSE)
return 0;
else {
/* only one valid case where server sends us request */
if(smb->Command == SMB_COM_LOCKING_ANDX)
return 0;
else
cERROR(1, ("\n Rcvd Request not response "));
}
} else { /* bad signature or mid */
if (*(unsigned int *) smb->Protocol != cpu_to_le32(0x424d53ff))
cERROR(1,
......@@ -252,8 +258,8 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
if (mid != smb->Mid)
cERROR(1, ("\n Mids do not match \n"));
}
cERROR(1, ("\nCIFS: bad smb detected. The Mid=%d\n", smb->Mid));
return 1;
cERROR(1, ("\nCIFS: bad smb detected. The Mid=%d\n", smb->Mid));
return 1;
}
int
......@@ -269,7 +275,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
cERROR(1, ("\n Length less than 2 + sizeof smb_hdr "));
if ((length >= sizeof (struct smb_hdr) - 1)
&& (smb->Status.CifsError != 0))
return 0; /* this is ok - some error cases do not return wct and bcc */
return 0; /* some error cases do not return wct and bcc */
}
if (4 + ntohl(smb->smb_buf_length) >
......@@ -298,30 +304,42 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
int
is_valid_oplock_break(struct smb_hdr *buf)
{
struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf;
/* could add check for smb response flag 0x80 */
cFYI(1,("\nChecking 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.WordCount != 8)
return FALSE;
cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel));
if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
return FALSE;
/* BB Add following logic:
1) look up tcon based on tid & uid
2) look up inode from tcon->openFileList->file->f_dentry->d_inode
3) flush dirty pages and cached byte range locks and mark inode
4) depending on break type change to r/o caching or no caching
5) send oplock break response to server */
cFYI(1,("\nNeed to process oplock break "));
return TRUE;
struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf;
struct list_head *tmp;
struct cifsTconInfo *tcon;
/* could add check for smb response flag 0x80 */
cFYI(1,("\nChecking 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.WordCount != 8)
return FALSE;
cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel));
if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
return FALSE;
/* look up tcon based on tid & uid */
read_lock(&GlobalSMBSeslock);
list_for_each(tmp, &GlobalTreeConnectionList) {
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
if (tcon->tid == buf->Tid)
if(tcon->ses->Suid == buf->Uid) {
/* BB Add following logic:
2) look up inode from tcon->openFileList->file->f_dentry->d_inode
3) flush dirty pages and cached byte range locks and mark inode
4) depending on break type change to r/o caching or no caching
5) send oplock break response to server */
read_unlock(&GlobalSMBSeslock);
cFYI(1,("\nFound matching connection, process oplock break"));
return TRUE;
}
}
read_unlock(&GlobalSMBSeslock);
cFYI(1,("\nProcessing oplock break for non-existent connection"));
return TRUE;
}
void
......
......@@ -745,7 +745,28 @@ const static struct {
ERRDOS, ERRnoaccess, 0xc0000290}, {
ERRDOS, ERRbadfunc, 0xc000029c},};
void
/*****************************************************************************
Print an error message from the status code
*****************************************************************************/
static void
cifs_print_status(__u32 status_code)
{
int idx = 0;
printk("\nStatus code returned: 0x%08x", status_code);
while (nt_errs[idx].nt_errstr != NULL) {
if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) ==
(status_code & 0xFFFFFF)) {
printk(nt_errs[idx].nt_errstr);
}
idx++;
}
return;
}
static void
ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode)
{
int i;
......@@ -781,9 +802,9 @@ map_smb_to_linux_error(struct smb_hdr *smb)
if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
/* translate the newer STATUS codes to old style errors and then to POSIX errors */
cFYI(1,
(" !!Mapping cifs error code %d ", smb->Status.CifsError));
smb->Status.CifsError = le32_to_cpu(smb->Status.CifsError);
if(cifsFYI)
cifs_print_status(smb->Status.CifsError);
ntstatus_to_dos(smb->Status.CifsError, &smberrclass,
&smberrcode);
} else {
......
......@@ -20,14 +20,9 @@
*/
/* NT error codes - see nterr.h */
#include "nterr.h"
#include <linux/types.h>
#include <linux/fs.h>
struct nt_err_code_struct {
char *nt_errstr;
__u32 nt_errcode;
};
#include "nterr.h"
const struct nt_err_code_struct nt_errs[] = {
{"NT_STATUS_OK", NT_STATUS_OK},
......@@ -690,23 +685,3 @@ const struct nt_err_code_struct nt_errs[] = {
{"STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED},
{NULL, 0}
};
/*****************************************************************************
Print an error message from the status code
*****************************************************************************/
/* void
cifs_print_status(__u32 status_code)
{
int idx = 0;
printk("\nStatus code returned: 0x%08x", status_code);
while (nt_errs[idx].nt_errstr != NULL) {
if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) ==
(status_code & 0xFFFFFF)) {
printk(nt_errs[idx].nt_errstr);
}
idx++;
}
return;
} */
......@@ -22,9 +22,18 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _NTERR_H
#define _NTERR_H
struct nt_err_code_struct {
char *nt_errstr;
__u32 nt_errcode;
};
extern const struct nt_err_code_struct nt_errs[];
/* Win32 Status codes. */
#define STATUS_BUFFER_OVERFLOW 0x80000005
......
......@@ -205,19 +205,26 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
/* Does the NTLMv2 owfs of a user's password */
void
ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
const char *domain_n, unsigned char kr_buf[16],
const struct nls_table *nls_codepage)
const char *domain_n, unsigned char kr_buf[16],
const struct nls_table *nls_codepage)
{
wchar_t user_u[1024];
wchar_t dom_u[1024];
wchar_t * user_u;
wchar_t * dom_u;
int user_l, domain_l;
struct HMACMD5Context ctx;
/* might as well do one alloc to hold both (user_u and dom_u) */
user_u = kmalloc(2048 * sizeof(wchar_t),GFP_KERNEL);
if(user_u == NULL)
return;
dom_u = user_u + 1024;
/* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */
/* do not think it is supposed to be uppercased */
int user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage);
int domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage);
/* do not think it is supposed to be uppercased */
user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage);
domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage);
user_l++; /* trailing null */
domain_l++;
......@@ -234,6 +241,7 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
dump_data(100, owf, 16);
dump_data(100, kr_buf, 16);
#endif
kfree(user_u);
}
/* Does the des encryption from the NT or LM MD4 hash. */
......
......@@ -59,9 +59,11 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
temp->tsk = current;
}
if (ses->status == CifsGood) {
write_lock(&GlobalMid_Lock);
list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
atomic_inc(&midCount);
temp->midState = MID_REQUEST_ALLOCATED;
write_unlock(&GlobalMid_Lock);
} else { /* BB add reconnect code here BB */
cERROR(1,
......@@ -77,11 +79,13 @@ void
DeleteMidQEntry(struct mid_q_entry *midEntry)
{
/* BB add spinlock to protect midq for each session BB */
write_lock(&GlobalMid_Lock);
midEntry->midState = MID_FREE;
buf_release(midEntry->resp_buf);
list_del(&midEntry->qhead);
kmem_cache_free(cifs_mid_cachep, midEntry);
atomic_dec(&midCount);
write_unlock(&GlobalMid_Lock);
buf_release(midEntry->resp_buf);
kmem_cache_free(cifs_mid_cachep, midEntry);
}
int
......@@ -93,8 +97,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
struct iovec iov;
mm_segment_t temp_fs;
if(ssocket == NULL)
return -ENOTSOCK; /* BB eventually add reconnect code here */
if(ssocket == NULL)
return -ENOTSOCK; /* BB eventually add reconnect code here */
/* ssocket->sk->allocation = GFP_BUFFER; *//* BB is this spurious? */
iov.iov_base = smb_buffer;
iov.iov_len = smb_buf_length + 4;
......@@ -159,8 +163,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
(struct sockaddr *) &(ses->server->sockAddr));
cFYI(1, ("\ncifs smb_send rc %d", rc)); /* BB remove */
/* BB add code to wait for response and copy to out_buf */
if (long_op > 1) /* writes past end of file can take a looooooong time */
timeout = 300 * HZ;
else if (long_op == 1)
......@@ -174,10 +176,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
/* Replace above line with wait_event to get rid of sleep_on per lk guidelines */
timeout = wait_event_interruptible_timeout(ses->server->response_q,
midQ->
midState &
MID_RESPONSE_RECEIVED,
15 * HZ);
midQ->
midState & MID_RESPONSE_RECEIVED,
timeout);
cFYI(1,
(" with timeout %ld and Out_buf: %p midQ->resp_buf: %p ", timeout,
out_buf, midQ->resp_buf));
......@@ -240,6 +241,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
rc = -EIO;
}
DeleteMidQEntry(midQ); /* BB what if process is killed ? - BB add background daemon to clean up Mid entries from killed processes BB test killing process with active mid */
DeleteMidQEntry(midQ); /* BB what if process is killed?
- BB add background daemon to clean up Mid entries from
killed processes & test killing process with active mid */
return rc;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment