Commit 058bee31 authored by Linus Torvalds's avatar Linus Torvalds

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

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 26623ba3 0e9f1916
...@@ -1562,7 +1562,7 @@ config SMB_NLS_REMOTE ...@@ -1562,7 +1562,7 @@ config SMB_NLS_REMOTE
smbmount from samba 2.2.0 or later supports this. smbmount from samba 2.2.0 or later supports this.
config CIFS config CIFS
tristate "CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)(EXPERIMENTAL)" tristate "CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)"
depends on INET depends on INET
select NLS select NLS
help help
...@@ -1592,7 +1592,16 @@ config CIFS_STATS ...@@ -1592,7 +1592,16 @@ config CIFS_STATS
depends on CIFS depends on CIFS
help help
Enabling this option will cause statistics for each server share Enabling this option will cause statistics for each server share
mounted by the cifs client to be displayed in /proc/fs/cifs/DebugData mounted by the cifs client to be displayed in /proc/fs/cifs/Stats
config CIFS_POSIX
bool "CIFS POSIX Extensions (EXPERIMENTAL)"
depends on CIFS
help
Enabling this option will cause the cifs client to attempt to
negotiate a newer dialect with servers, such as Samba 3.0.5
or later, that optionally can handle more POSIX like (rather
than Windows like) file behavior. If unsure, say N.
config NCP_FS config NCP_FS
tristate "NCP file system support (to mount NetWare volumes)" tristate "NCP file system support (to mount NetWare volumes)"
......
...@@ -31,7 +31,7 @@ Thanks to those in the community who have submitted detailed bug reports ...@@ -31,7 +31,7 @@ Thanks to those in the community who have submitted detailed bug reports
and debug of problems they have found: Jochen Dolze, David Blaine, and debug of problems they have found: Jochen Dolze, David Blaine,
Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori, Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori,
Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen, Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen,
Olaf Kirch, Kieron Briggs and others. Olaf Kirch, Kieron Briggs, Nick Millington and others.
And thanks to the IBM LTC and Power test teams and SuSE testers for And thanks to the IBM LTC and Power test teams and SuSE testers for
finding multiple bugs during excellent stress test runs. finding multiple bugs during excellent stress test runs.
Version 1.19
------------
Fix /proc/fs/cifs/Stats and DebugData display to handle larger
amounts of return data. Properly limit requests to MAX_REQ (50
is the usual maximum active multiplex SMB/CIFS requests per server).
Do not kill cifsd (and thus hurt the other SMB session) when more than one
session to the same server (but with different userids) exists and one
of the two user's smb sessions is being removed while leaving the other.
Version 1.18 Version 1.18
------------ ------------
Do not rename hardlinked files (since that should be a noop). Flush Do not rename hardlinked files (since that should be a noop). Flush
cached write behind data when reopening a file after session abend, cached write behind data when reopening a file after session abend,
except when already in write. Grab per socket sem during reconnect except when already in write. Grab per socket sem during reconnect
to avoid oops in sendmsg if overlapping with reconnect. to avoid oops in sendmsg if overlapping with reconnect. Do not
reset cached inode file size on readdir for files open for write on
client.
Version 1.17 Version 1.17
......
...@@ -62,12 +62,17 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -62,12 +62,17 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
int count, int *eof, void *data) int count, int *eof, void *data)
{ {
struct list_head *tmp; struct list_head *tmp;
struct list_head *tmp1;
struct mid_q_entry * mid_entry;
struct cifsSesInfo *ses; struct cifsSesInfo *ses;
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
int i; int i;
int length = 0; int length = 0;
char *buf_start = buf; char * original_buf = buf;
*beginBuffer = buf + offset;
length = length =
sprintf(buf, sprintf(buf,
"Display Internal CIFS Data Structures for Debugging\n" "Display Internal CIFS Data Structures for Debugging\n"
...@@ -94,7 +99,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -94,7 +99,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
ses->server->secMode, ses->server->secMode,
atomic_read(&ses->server->inFlight)); atomic_read(&ses->server->inFlight));
/* length = sprintf(buf, "\nMIDs: \n"); length = sprintf(buf, "\nMIDs: \n");
buf += length; buf += length;
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
...@@ -103,11 +108,11 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -103,11 +108,11 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
mid_q_entry, mid_q_entry,
qhead); qhead);
if(mid_entry) { 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); length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n",mid_entry->midState,mid_entry->command,mid_entry->pid,mid_entry->tsk,mid_entry->mid);
buf += length; buf += length;
} }
} }
spin_unlock(&GlobalMid_Lock); */ spin_unlock(&GlobalMid_Lock);
} }
} }
...@@ -152,19 +157,22 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ...@@ -152,19 +157,22 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
length = sprintf(buf, "\n"); length = sprintf(buf, "\n");
buf += length; buf += length;
*eof = 1;
/* BB add code to dump additional info such as TCP session info now */ /* BB add code to dump additional info such as TCP session info now */
/* /* Now calculate total size of returned data */
if (offset >= (buf - buf_start)) length = buf - original_buf;
{
*beginBuffer = buf; if(offset + count >= length)
return 0; *eof = 1;
} if(length < offset) {
*beginBuffer = buf + offset; *eof = 1;
if ((buf - buf_start - offset) > count) return 0;
return count; } else {
else */ length = length - offset;
return (buf - buf_start - offset); }
if (length > count)
length = count;
return length;
} }
int int
...@@ -183,12 +191,14 @@ cifs_total_xid_read(char *buf, char **beginBuffer, off_t offset, ...@@ -183,12 +191,14 @@ cifs_total_xid_read(char *buf, char **beginBuffer, off_t offset,
#ifdef CONFIG_CIFS_STATS #ifdef CONFIG_CIFS_STATS
int int
cifs_stats_read(char *buf, char **beginBuffer, off_t offset, cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
int length, int *eof, void *data) int count, int *eof, void *data)
{ {
int item_length,i; int item_length,i,length;
struct list_head *tmp; struct list_head *tmp;
struct cifsTconInfo *tcon; struct cifsTconInfo *tcon;
*beginBuffer = buf + offset;
length = sprintf(buf, length = sprintf(buf,
"Resources in use\nCIFS Session: %d\n", "Resources in use\nCIFS Session: %d\n",
sesInfoAllocCount.counter); sesInfoAllocCount.counter);
...@@ -235,10 +245,12 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, ...@@ -235,10 +245,12 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
atomic_read(&tcon->num_reads), atomic_read(&tcon->num_reads),
(long long)(tcon->bytes_read)); (long long)(tcon->bytes_read));
buf += item_length; buf += item_length;
length += item_length;
item_length = sprintf(buf,"\nWrites: %d Bytes: %lld", item_length = sprintf(buf,"\nWrites: %d Bytes: %lld",
atomic_read(&tcon->num_writes), atomic_read(&tcon->num_writes),
(long long)(tcon->bytes_written)); (long long)(tcon->bytes_written));
buf += item_length; buf += item_length;
length += item_length;
item_length = sprintf(buf, item_length = sprintf(buf,
"\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d", "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d",
atomic_read(&tcon->num_opens), atomic_read(&tcon->num_opens),
...@@ -247,10 +259,29 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, ...@@ -247,10 +259,29 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
atomic_read(&tcon->num_rmdirs)); atomic_read(&tcon->num_rmdirs));
buf += item_length; buf += item_length;
length += item_length; length += item_length;
item_length = sprintf(buf,
"\nRenames: %d T2 Renames %d",
atomic_read(&tcon->num_renames),
atomic_read(&tcon->num_t2renames));
buf += item_length;
length += item_length;
} }
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
buf += sprintf(buf,"\n");
length++;
if(offset + count >= length)
*eof = 1;
if(length < offset) {
*eof = 1;
return 0;
} else {
length = length - offset;
}
if (length > count)
length = count;
return length; return length;
} }
#endif #endif
......
...@@ -93,5 +93,5 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *, ...@@ -93,5 +93,5 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *,
size_t, int); size_t, int);
extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
#define CIFS_VERSION "1.18" #define CIFS_VERSION "1.19"
#endif /* _CIFSFS_H */ #endif /* _CIFSFS_H */
...@@ -211,6 +211,8 @@ struct cifsTconInfo { ...@@ -211,6 +211,8 @@ struct cifsTconInfo {
atomic_t num_deletes; atomic_t num_deletes;
atomic_t num_mkdirs; atomic_t num_mkdirs;
atomic_t num_rmdirs; atomic_t num_rmdirs;
atomic_t num_renames;
atomic_t num_t2renames;
__u64 bytes_read; __u64 bytes_read;
__u64 bytes_written; __u64 bytes_written;
spinlock_t stat_lock; spinlock_t stat_lock;
......
...@@ -387,6 +387,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) ...@@ -387,6 +387,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
ses->server->tcpStatus = CifsExiting; ses->server->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
rc = -ESHUTDOWN;
} }
} }
if (pSMB) if (pSMB)
...@@ -819,14 +820,20 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, ...@@ -819,14 +820,20 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
pSMB->AndXCommand = 0xFF; /* none */ pSMB->AndXCommand = 0xFF; /* none */
pSMB->Fid = smb_file_id; /* netfid stays le */ pSMB->Fid = smb_file_id; /* netfid stays le */
pSMB->Locks[0].Pid = cpu_to_le16(current->tgid); if(numLock != 0) {
temp = cpu_to_le64(len); pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
pSMB->Locks[0].LengthLow = (__u32)(len & 0xFFFFFFFF); /* BB where to store pid high? */
pSMB->Locks[0].LengthHigh = (__u32)(len>>32); temp = cpu_to_le64(len);
temp = cpu_to_le64(offset); pSMB->Locks[0].LengthLow = (__u32)(temp & 0xFFFFFFFF);
pSMB->Locks[0].OffsetLow = (__u32)(offset & 0xFFFFFFFF); pSMB->Locks[0].LengthHigh = (__u32)(temp>>32);
pSMB->Locks[0].OffsetHigh = (__u32)(offset>>32); temp = cpu_to_le64(offset);
pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE); pSMB->Locks[0].OffsetLow = (__u32)(temp & 0xFFFFFFFF);
pSMB->Locks[0].OffsetHigh = (__u32)(temp>>32);
pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE);
} else {
/* oplock break */
pSMB->ByteCount = 0;
}
pSMB->hdr.smb_buf_length += pSMB->ByteCount; pSMB->hdr.smb_buf_length += pSMB->ByteCount;
pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
...@@ -941,7 +948,14 @@ CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, ...@@ -941,7 +948,14 @@ CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
(struct smb_hdr *) pSMBr, &bytes_returned, 0); (struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) { if (rc) {
cFYI(1, ("Send error in rename = %d", rc)); cFYI(1, ("Send error in rename = %d", rc));
}
#ifdef CONFIG_CIFS_STATS
else {
atomic_inc(&tcon->num_renames);
} }
#endif
if (pSMB) if (pSMB)
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
...@@ -1017,7 +1031,11 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, ...@@ -1017,7 +1031,11 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
if (rc) { if (rc) {
cFYI(1,("Send error in Rename (by file handle) = %d", rc)); cFYI(1,("Send error in Rename (by file handle) = %d", rc));
} }
#ifdef CONFIG_CIFS_STATS
else {
atomic_inc(&pTcon->num_t2renames);
}
#endif
if (pSMB) if (pSMB)
cifs_buf_release(pSMB); cifs_buf_release(pSMB);
......
...@@ -175,7 +175,7 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -175,7 +175,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
if(server->tcpStatus != CifsExiting) if(server->tcpStatus != CifsExiting)
server->tcpStatus = CifsGood; server->tcpStatus = CifsGood;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
atomic_set(&server->inFlight,0); /* atomic_set(&server->inFlight,0);*/
wake_up(&server->response_q); wake_up(&server->response_q);
} }
} }
...@@ -453,7 +453,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -453,7 +453,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
read_unlock(&GlobalSMBSeslock); read_unlock(&GlobalSMBSeslock);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
/* 1/8th of sec should be more than enough time for them to exit */ /* 1/8th of sec is more than enough time for them to exit */
schedule_timeout(HZ/8); schedule_timeout(HZ/8);
} }
...@@ -468,7 +468,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) ...@@ -468,7 +468,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} }
kfree(server); kfree(server);
cFYI(1, ("About to exit from demultiplex thread")); set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ/4);
return 0; return 0;
} }
...@@ -2769,6 +2770,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) ...@@ -2769,6 +2770,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
int rc = 0; int rc = 0;
int xid; int xid;
struct cifsSesInfo *ses = NULL; struct cifsSesInfo *ses = NULL;
struct task_struct *cifsd_task;
xid = GetXid(); xid = GetXid();
...@@ -2781,19 +2783,25 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) ...@@ -2781,19 +2783,25 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
} }
tconInfoFree(cifs_sb->tcon); tconInfoFree(cifs_sb->tcon);
if ((ses) && (ses->server)) { if ((ses) && (ses->server)) {
/* save off task so we do not refer to ses later */
cifsd_task = ses->server->tsk;
cFYI(1, ("About to do SMBLogoff ")); cFYI(1, ("About to do SMBLogoff "));
rc = CIFSSMBLogoff(xid, ses); rc = CIFSSMBLogoff(xid, ses);
if (rc == -EBUSY) { if (rc == -EBUSY) {
FreeXid(xid); FreeXid(xid);
return 0; return 0;
} } else if (rc == -ESHUTDOWN) {
/* should we add wake_up_all(&server->request_q);
set_current_state(TASK_INTERRUPTIBLE); and add a check in the check inFlight loop
schedule_timeout(HZ / 4); /* give captive thread time to exit */ for the session ending */
if((ses->server) && (ses->server->ssocket)) { set_current_state(TASK_INTERRUPTIBLE);
cFYI(1,("Waking up socket by sending it signal ")); /* give captive thread time to exit */
send_sig(SIGKILL,ses->server->tsk,1); schedule_timeout(HZ / 4);
} cFYI(1,("Waking up socket by sending it signal"));
send_sig(SIGKILL,cifsd_task,1);
rc = 0;
} /* else - we have an smb session
left on this socket do not kill cifsd */
} else } else
cFYI(1, ("No session or bad tcon")); cFYI(1, ("No session or bad tcon"));
} }
......
...@@ -588,9 +588,10 @@ cifs_write(struct file * file, const char *write_data, ...@@ -588,9 +588,10 @@ cifs_write(struct file * file, const char *write_data,
if(file->f_dentry == NULL) if(file->f_dentry == NULL)
return -EBADF; return -EBADF;
xid = GetXid();
cifs_sb = CIFS_SB(file->f_dentry->d_sb); cifs_sb = CIFS_SB(file->f_dentry->d_sb);
if(cifs_sb == NULL) {
return -EBADF;
}
pTcon = cifs_sb->tcon; pTcon = cifs_sb->tcon;
/*cFYI(1, /*cFYI(1,
...@@ -598,11 +599,12 @@ cifs_write(struct file * file, const char *write_data, ...@@ -598,11 +599,12 @@ cifs_write(struct file * file, const char *write_data,
*poffset, file->f_dentry->d_name.name)); */ *poffset, file->f_dentry->d_name.name)); */
if (file->private_data == NULL) { if (file->private_data == NULL) {
FreeXid(xid);
return -EBADF; return -EBADF;
} else {
open_file = (struct cifsFileInfo *) file->private_data;
} }
open_file = (struct cifsFileInfo *) file->private_data;
xid = GetXid();
if(file->f_dentry->d_inode == NULL) { if(file->f_dentry->d_inode == NULL) {
FreeXid(xid); FreeXid(xid);
return -EBADF; return -EBADF;
...@@ -620,10 +622,22 @@ cifs_write(struct file * file, const char *write_data, ...@@ -620,10 +622,22 @@ cifs_write(struct file * file, const char *write_data,
if(file->private_data == NULL) { if(file->private_data == NULL) {
/* file has been closed on us */ /* file has been closed on us */
FreeXid(xid); FreeXid(xid);
/* if we have gotten here we have written some data
and blocked, and the file has been freed on us
while we blocked so return what we managed to write */
return total_written; return total_written;
}
open_file = (struct cifsFileInfo *) file->private_data;
if(open_file->closePend) {
FreeXid(xid);
if(total_written)
return total_written;
else
return -EBADF;
} }
if ((open_file->invalidHandle) && (!open_file->closePend)) { if (open_file->invalidHandle) {
if((file->f_dentry == NULL) || (file->f_dentry->d_inode == NULL)) { if((file->f_dentry == NULL) ||
(file->f_dentry->d_inode == NULL)) {
FreeXid(xid); FreeXid(xid);
return total_written; return total_written;
} }
......
...@@ -200,23 +200,35 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -200,23 +200,35 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
} }
/* Ensure that we do not send more than 50 overlapping requests /* Ensure that we do not send more than 50 overlapping requests
to the same server. We may make this configurable later or to the same server. We may make this configurable later or
use ses->maxReq */ use ses->maxReq */
if(long_op == -1) {
/* can not count locking commands against the total since /* oplock breaks must not be held up */
they are allowed to block on server */ atomic_inc(&ses->server->inFlight);
if(long_op < 3) { } else {
/* update # of requests on the wire to this server */ spin_lock(&GlobalMid_Lock);
atomic_inc(&ses->server->inFlight); while(1) {
} if(atomic_read(&ses->server->inFlight) >= CIFS_MAX_REQ){
spin_unlock(&GlobalMid_Lock);
if(atomic_read(&ses->server->inFlight) > CIFS_MAX_REQ) { wait_event(ses->server->request_q,
wait_event(ses->server->request_q,atomic_read(&ses->server->inFlight) <= CIFS_MAX_REQ); atomic_read(&ses->server->inFlight)
< CIFS_MAX_REQ);
spin_lock(&GlobalMid_Lock);
} else {
/* can not count locking commands against total since
they are allowed to block on server */
if(long_op < 3) {
/* update # of requests on the wire to server */
atomic_inc(&ses->server->inFlight);
}
spin_unlock(&GlobalMid_Lock);
break;
}
}
} }
/* make sure that we sign in the same order that we send on this socket /* 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 and avoid races inside tcp sendmsg code that could cause corruption
of smb data */ of smb data */
down(&ses->server->tcpSem); down(&ses->server->tcpSem);
......
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