Commit aa299b22 authored by Zwane Mwaikambo's avatar Zwane Mwaikambo Committed by Linus Torvalds

[PATCH] Fix smbfs readdir oops

This has been reported a couple of times and is consistently causing some
folks grief, so Urban, would you mind terribly if i send this patch to at
least clear current bug reports.  If there is additional stuff you want
ontop of this let me know and i can send a follow up patch.

The bug is that at times we haven't completed setting up the smb_ops so we
have a temporary 'null' ops in place until the connection is completely up.
 With this setup it's possible to hit ->readdir() whilst the null ops are
still in place, so we put the process to sleep until the connection setup
is complete and then call the real ->readdir().

This patch addresses the bugzilla report at
http://bugzilla.kernel.org/show_bug.cgi?id=1671Signed-off-by: default avatarZwane Mwaikambo <zwane@linuxpower.ca>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 81c3dade
...@@ -521,6 +521,7 @@ int smb_fill_super(struct super_block *sb, void *raw_data, int silent) ...@@ -521,6 +521,7 @@ int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
server->super_block = sb; server->super_block = sb;
server->mnt = NULL; server->mnt = NULL;
server->sock_file = NULL; server->sock_file = NULL;
init_waitqueue_head(&server->conn_wq);
init_MUTEX(&server->sem); init_MUTEX(&server->sem);
INIT_LIST_HEAD(&server->entry); INIT_LIST_HEAD(&server->entry);
INIT_LIST_HEAD(&server->xmitq); INIT_LIST_HEAD(&server->xmitq);
......
...@@ -56,6 +56,7 @@ static struct smb_ops smb_ops_os2; ...@@ -56,6 +56,7 @@ static struct smb_ops smb_ops_os2;
static struct smb_ops smb_ops_win95; static struct smb_ops smb_ops_win95;
static struct smb_ops smb_ops_winNT; static struct smb_ops smb_ops_winNT;
static struct smb_ops smb_ops_unix; static struct smb_ops smb_ops_unix;
static struct smb_ops smb_ops_null;
static void static void
smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr); smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);
...@@ -981,6 +982,9 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt) ...@@ -981,6 +982,9 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
smbiod_wake_up(); smbiod_wake_up();
if (server->opt.capabilities & SMB_CAP_UNIX) if (server->opt.capabilities & SMB_CAP_UNIX)
smb_proc_query_cifsunix(server); smb_proc_query_cifsunix(server);
server->conn_complete++;
wake_up_interruptible_all(&server->conn_wq);
return error; return error;
out: out:
...@@ -2793,11 +2797,46 @@ smb_proc_getattr_95(struct smb_sb_info *server, struct dentry *dir, ...@@ -2793,11 +2797,46 @@ smb_proc_getattr_95(struct smb_sb_info *server, struct dentry *dir,
return result; return result;
} }
static int
smb_proc_ops_wait(struct smb_sb_info *server)
{
int result;
result = wait_event_interruptible_timeout(server->conn_wq,
server->conn_complete, 30*HZ);
if (!result || signal_pending(current))
return -EIO;
return 0;
}
static int static int
smb_proc_getattr_null(struct smb_sb_info *server, struct dentry *dir, smb_proc_getattr_null(struct smb_sb_info *server, struct dentry *dir,
struct smb_fattr *attr) struct smb_fattr *fattr)
{ {
return -EIO; int result;
if (smb_proc_ops_wait(server) < 0)
return -EIO;
smb_init_dirent(server, fattr);
result = server->ops->getattr(server, dir, fattr);
smb_finish_dirent(server, fattr);
return result;
}
static int
smb_proc_readdir_null(struct file *filp, void *dirent, filldir_t filldir,
struct smb_cache_control *ctl)
{
struct smb_sb_info *server = server_from_dentry(filp->f_dentry);
if (smb_proc_ops_wait(server) < 0)
return -EIO;
return server->ops->readdir(filp, dirent, filldir, ctl);
} }
int int
...@@ -3431,6 +3470,7 @@ static struct smb_ops smb_ops_unix = ...@@ -3431,6 +3470,7 @@ static struct smb_ops smb_ops_unix =
/* Place holder until real ops are in place */ /* Place holder until real ops are in place */
static struct smb_ops smb_ops_null = static struct smb_ops smb_ops_null =
{ {
.readdir = smb_proc_readdir_null,
.getattr = smb_proc_getattr_null, .getattr = smb_proc_getattr_null,
}; };
......
...@@ -57,7 +57,8 @@ struct smb_sb_info { ...@@ -57,7 +57,8 @@ struct smb_sb_info {
unsigned int generation; unsigned int generation;
pid_t conn_pid; pid_t conn_pid;
struct smb_conn_opt opt; struct smb_conn_opt opt;
wait_queue_head_t conn_wq;
int conn_complete;
struct semaphore sem; struct semaphore sem;
unsigned char header[SMB_HEADER_LEN + 20*2 + 2]; unsigned char header[SMB_HEADER_LEN + 20*2 + 2];
......
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