patch-2.4.20 linux-2.4.20/fs/smbfs/sock.c

Next file: linux-2.4.20/fs/super.c
Previous file: linux-2.4.20/fs/smbfs/smb_debug.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/fs/smbfs/sock.c linux-2.4.20/fs/smbfs/sock.c
@@ -12,6 +12,7 @@
 #include <linux/socket.h>
 #include <linux/fcntl.h>
 #include <linux/file.h>
+#include <linux/poll.h>
 #include <linux/in.h>
 #include <linux/net.h>
 #include <linux/mm.h>
@@ -305,6 +306,55 @@
 	}
 }
 
+/*
+ * Poll the server->socket to allow receives to time out.
+ * returns 0 when ok to continue, <0 on errors.
+ */
+static int
+smb_receive_poll(struct smb_sb_info *server)
+{
+	struct file *file = server->sock_file;
+	poll_table wait_table;
+	int result = 0;
+	int timeout = server->mnt->timeo * HZ;
+	int mask;
+
+	for (;;) {
+		poll_initwait(&wait_table);
+                set_current_state(TASK_INTERRUPTIBLE);
+
+		mask = file->f_op->poll(file, &wait_table);
+		if (mask & POLLIN) {
+			poll_freewait(&wait_table);
+			current->state = TASK_RUNNING;
+			break;
+		}
+
+		timeout = schedule_timeout(timeout);
+		poll_freewait(&wait_table);
+                set_current_state(TASK_RUNNING);
+
+		if (wait_table.error) {
+			result = wait_table.error;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			/* we got a signal (which?) tell the caller to
+			   try again (on all signals?). */
+			DEBUG1("got signal_pending()\n");
+			result = -ERESTARTSYS;
+			break;
+		}
+		if (!timeout) {
+			printk(KERN_WARNING "SMB server not responding\n");
+			result = -EIO;
+			break;
+		}
+	}
+	return result;
+}
+
 static int
 smb_send_raw(struct socket *socket, unsigned char *source, int length)
 {
@@ -332,13 +382,19 @@
 }
 
 static int
-smb_receive_raw(struct socket *socket, unsigned char *target, int length)
+smb_receive_raw(struct smb_sb_info *server, unsigned char *target, int length)
 {
 	int result;
 	int already_read = 0;
+	struct socket *socket = server_sock(server);
 
 	while (already_read < length)
 	{
+		result = smb_receive_poll(server);
+		if (result < 0) {
+			DEBUG1("poll error = %d\n", -result);
+			return result;
+		}
 		result = _recvfrom(socket,
 				   (void *) (target + already_read),
 				   length - already_read, 0);
@@ -358,7 +414,7 @@
 }
 
 static int
-smb_get_length(struct socket *socket, unsigned char *header)
+smb_get_length(struct smb_sb_info *server, unsigned char *header)
 {
 	int result;
 	unsigned char peek_buf[4];
@@ -367,7 +423,7 @@
       re_recv:
 	fs = get_fs();
 	set_fs(get_ds());
-	result = smb_receive_raw(socket, peek_buf, 4);
+	result = smb_receive_raw(server, peek_buf, 4);
 	set_fs(fs);
 
 	if (result < 0)
@@ -415,12 +471,11 @@
 static int
 smb_receive(struct smb_sb_info *server)
 {
-	struct socket *socket = server_sock(server);
 	unsigned char * packet = server->packet;
 	int len, result;
 	unsigned char peek_buf[4];
 
-	result = smb_get_length(socket, peek_buf);
+	result = smb_get_length(server, peek_buf);
 	if (result < 0)
 		goto out;
 	len = result;
@@ -442,7 +497,7 @@
 		server->packet_size = new_len;
 	}
 	memcpy(packet, peek_buf, 4);
-	result = smb_receive_raw(socket, packet + 4, len);
+	result = smb_receive_raw(server, packet + 4, len);
 	if (result < 0)
 	{
 		VERBOSE("receive error: %d\n", result);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)