problem: smbmounted share cannot see all files

Urban Widmark urban at svenskatest.se
Mon Oct 9 12:39:55 GMT 2000


On Tue, 3 Oct 2000, Andrew Oliver wrote:

> 
> I have a RH 6.2 system with Samba "2.07-4".  My
> problem is that no *.bat and *.cmd files are visible
> to the samba mounted share in a paticular 3rd layer
> directory (to ls or cp).  I am assuming the remote
> machine is an NT4 server.  The bat and cmd files ARE

[Note to the list, it turned out to be an OS/2 box]

> Sep 26 10:43:56 acoliver98 kernel: smb_receive_trans2:
> copied, parm=4079 of 4079, data=220 of 4079
> Sep 26 10:43:56 acoliver98 kernel: smb_receive_trans2:
> copied, parm=4079 of 4079, data=4079 of 4079

Could you try the attached patch vs 2.2.18-pre15
(You need 2.2.17 + pre-patch-2.2.18-15.gz and then the attached patch)

Anyone else seeing wierd things with dir listings should test this too.
Please.


smbfs is asking the server to return more data than the negotiated maximum
transfer size. This causes things to not work with NT4 and is possibly the
reason for why OS/2 returns data that needs extra allocation+copy.

(NT4 testcase: make a dir with directories 001 - 083 on NTFS, the listing
 over smbfs should fail).

/Urban
-------------- next part --------------
diff -ur -X exclude linux-2.2.18-pre15-orig/fs/smbfs/proc.c linux-2.2.18-pre15-smbfs/fs/smbfs/proc.c
--- linux-2.2.18-pre15-orig/fs/smbfs/proc.c	Sun Oct  8 13:22:26 2000
+++ linux-2.2.18-pre15-smbfs/fs/smbfs/proc.c	Sun Oct  8 21:45:32 2000
@@ -385,22 +385,16 @@
 }
 
 /*
- * Returns the maximum read or write size for the current packet size
- * and max_xmit value.
+ * Returns the maximum read or write size for the "payload". Making all of the
+ * packet fit within the negotiated max_xmit size.
+ *
  * N.B. Since this value is usually computed before locking the server,
  * the server's packet size must never be decreased!
  */
-static int
+static inline int
 smb_get_xmitsize(struct smb_sb_info *server, int overhead)
 {
-	int size = server->packet_size;
-
-	/*
-	 * Start with the smaller of packet size and max_xmit ...
-	 */
-	if (size > server->opt.max_xmit)
-		size = server->opt.max_xmit;
-	return size - overhead;
+	return server->opt.max_xmit - overhead;
 }
 
 /*
@@ -751,6 +745,23 @@
 		server->opt.protocol, server->opt.max_xmit, server->conn_pid,
 		server->opt.capabilities);
 
+	/* Make sure we can fit a message of the negotiated size in our
+	   packet buffer. */
+	if (server->opt.max_xmit > server->packet_size) {
+		int len = smb_round_length(server->opt.max_xmit);
+		char *buf = smb_vmalloc(len);
+		if (buf) {
+			server->packet = buf;
+			server->packet_size = len;
+		} else {
+			/* else continue with the too small buffer? */
+			PARANOIA("Failed to allocate new packet buffer: "
+				 "max_xmit=%d, packet_size=%d\n",
+				 server->opt.max_xmit, server->packet_size);
+			server->opt.max_xmit = server->packet_size;
+		}
+	}
+
 out:
 #ifdef SMB_RETRY_INTR
 	wake_up_interruptible(&server->wait);
@@ -1487,8 +1498,8 @@
 smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
 		      void *cachep)
 {
-	unsigned char *p;
-	char *mask, *lastname, *param = server->temp_buf;
+	unsigned char *p, *lastname;
+	char *mask, *param = server->temp_buf;
 	__u16 command;
 	int first, entries, entries_seen;
 
@@ -1521,7 +1532,7 @@
 	 * Encode the initial path
 	 */
 	mask = param + 12;
-	mask_len = smb_encode_path(server, mask, dir, &star);
+	mask_len = smb_encode_path(server, mask, dir, &star) - 1;
 	if (mask_len < 0) {
 		entries = mask_len;
 		goto unlock_return;
@@ -1613,31 +1624,41 @@
 		if (ff_searchcount == 0)
 			break;
 
-		/* we might need the lastname for continuations */
+		/*
+		 * We might need the lastname for continuations.
+		 *
+		 * Note that some servers (win95) point to the filename and
+		 * others (NT4, Samba using NT1) to the dir entry. We assume
+		 * here that those who do not point to a filename do not need
+		 * this info to continue the listing.
+		 */
 		mask_len = 0;
-		if (ff_lastname > 0) {
+		if (ff_lastname > 0 && ff_lastname < resp_data_len) {
 			lastname = resp_data + ff_lastname;
 			switch (info_level) {
 			case 260:
-				if (ff_lastname < resp_data_len)
-					mask_len = resp_data_len - ff_lastname;
+				mask_len = resp_data_len - ff_lastname;
 				break;
 			case 1:
-				/* Win NT 4.0 doesn't set the length byte */
-				lastname++;
-				if (ff_lastname + 2 < resp_data_len)
-					mask_len = strlen(lastname);
+				/* lastname points to a length byte */
+				mask_len = *lastname++;
+				if (ff_lastname + 1 + mask_len > resp_data_len)
+					mask_len = resp_data_len - ff_lastname - 1;
 				break;
 			}
 			/*
 			 * Update the mask string for the next message.
 			 */
+			if (mask_len < 0)
+				mask_len = 0;
 			if (mask_len > 255)
 				mask_len = 255;
 			if (mask_len)
 				strncpy(mask, lastname, mask_len);
 		}
 		mask[mask_len] = 0;
+		mask_len = strlen(mask);	/* find the actual string len */
+
 
 		/* Now we are ready to parse smb directory entries. */
 
diff -ur -X exclude linux-2.2.18-pre15-orig/fs/smbfs/sock.c linux-2.2.18-pre15-smbfs/fs/smbfs/sock.c
--- linux-2.2.18-pre15-orig/fs/smbfs/sock.c	Sun Oct  8 13:22:26 2000
+++ linux-2.2.18-pre15-smbfs/fs/smbfs/sock.c	Sun Oct  8 18:23:42 2000
@@ -520,12 +520,10 @@
 				goto success;
 			}
 
-			if (parm_tot > TRANS2_MAX_TRANSFER ||
-	  		    data_tot > TRANS2_MAX_TRANSFER)
-				goto out_too_long;
-
 			/*
-			 * Save the total parameter and data length.
+			 * Allocate a new buffer for receiving multiple packets
+			 * into. If we stick to the negotiated max_xmit this
+			 * shouldn't have to happen.
 			 */
 			total_d = data_tot;
 			total_p = parm_tot;
@@ -534,6 +532,8 @@
 			if (server->packet_size > buf_len)
 				buf_len = server->packet_size;
 			buf_len = smb_round_length(buf_len);
+			if (buf_len > SMB_MAX_PACKET_SIZE)
+				goto out_no_mem;
 
 			rcv_buf = smb_vmalloc(buf_len);
 			if (!rcv_buf)
@@ -713,6 +713,7 @@
 	struct socket *sock = server_sock(server);
 	struct scm_cookie scm;
 	int err;
+	int mparam, mdata;
 
 	/* I know the following is very ugly, but I want to build the
 	   smb packet as efficiently as possible. */
@@ -733,19 +734,25 @@
 	struct iovec iov[4];
 	struct msghdr msg;
 
-	/* N.B. This test isn't valid! packet_size may be < max_xmit */
+	/* FIXME! this test needs to include SMB overhead too, I think ... */
 	if ((bcc + oparam) > server->opt.max_xmit)
-	{
 		return -ENOMEM;
-	}
 	p = smb_setup_header(server, SMBtrans2, smb_parameters, bcc);
 
+	/* max parameters + max data + max setup == max_xmit to make NT4 happy
+	   and not abort the transfer or split into multiple packets. */
+	mparam = SMB_TRANS2_MAX_PARAM;
+	mdata = server->opt.max_xmit - mparam;
+	if (mdata < 1024) {
+		mdata = 1024;
+		mparam = server->opt.max_xmit - mdata;
+	}
+
 	WSET(server->packet, smb_tpscnt, lparam);
 	WSET(server->packet, smb_tdscnt, ldata);
-	/* N.B. these values should reflect out current packet size */
-	WSET(server->packet, smb_mprcnt, TRANS2_MAX_TRANSFER);
-	WSET(server->packet, smb_mdrcnt, TRANS2_MAX_TRANSFER);
-	WSET(server->packet, smb_msrcnt, 0);
+	WSET(server->packet, smb_mprcnt, mparam);
+	WSET(server->packet, smb_mdrcnt, mdata);
+	WSET(server->packet, smb_msrcnt, 0);	/* max setup always 0 ? */
 	WSET(server->packet, smb_flags, 0);
 	DSET(server->packet, smb_timeout, 0);
 	WSET(server->packet, smb_pscnt, lparam);
diff -ur -X exclude linux-2.2.18-pre15-orig/include/linux/smb.h linux-2.2.18-pre15-smbfs/include/linux/smb.h
--- linux-2.2.18-pre15-orig/include/linux/smb.h	Sun Oct  8 13:22:28 2000
+++ linux-2.2.18-pre15-smbfs/include/linux/smb.h	Sun Oct  8 18:17:10 2000
@@ -119,11 +119,12 @@
 
 #define SMB_HEADER_LEN   37     /* includes everything up to, but not
                                  * including smb_bcc */
-#define SMB_DEF_MAX_XMIT 32768
-#define SMB_INITIAL_PACKET_SIZE 4000
 
-/* Allocate max. 1 page */
-#define TRANS2_MAX_TRANSFER (4096-17)
+#define SMB_INITIAL_PACKET_SIZE	4000
+#define SMB_MAX_PACKET_SIZE	32768
+
+/* reserve this much space for trans2 parameters */
+#define SMB_TRANS2_MAX_PARAM 200
 
 #endif
 #endif


More information about the samba mailing list