[linux-cifs-client] [DFS support patchset: ] [2/5]: CIFSGetDFSRefer is rewritten to return more information about DFS refferal.

Q (Igor Mammedov) qwerty0987654321 at mail.ru
Tue Dec 18 14:15:30 GMT 2007


 1. Now CIFSGetDFSRefer returns array of struct dfs_info3_param that has
    necessary parameters for handling connect to refferal storage node.
 2. Some formating changes to CIFSGetDFSRefer for the sake of checkpatch.
 3. Unused function connect_to_dfs_path now return ENOSYS till we decide
    what to do with it.
 4. Commented out usage of get_dfs_path in cifs_readlink. We don't need it.

Signed-off-by: Igor Mammedov <niallain at gmail.com>
---
 fs/cifs/cifsglob.h  |   36 +++++++++
 fs/cifs/cifsproto.h |    6 +-
 fs/cifs/cifssmb.c   |  214 +++++++++++++++++++++++++++++++--------------------
 fs/cifs/connect.c   |   14 ++-
 fs/cifs/link.c      |    3 +
 5 files changed, 183 insertions(+), 90 deletions(-)

diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 1fde219..50df0d8 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -460,6 +460,42 @@ struct dir_notify_req {
        struct file *pfile;
 };
 
+struct dfs_info3_param {
+	int flags; /* DFSREF_REFERRAL_SERVER, DFSREF_STORAGE_SERVER*/
+	int PathConsumed;
+	int server_type;
+	int ref_flag;
+	char *path_name;
+	char *node_name;
+};
+
+static inline void init_dfs_info_param(struct dfs_info3_param *param)
+{
+	memset(param, 0, sizeof(struct dfs_info3_param));
+}
+
+static inline void free_dfs_info_param(struct dfs_info3_param *param)
+{
+	if (param) {
+		kfree(param->path_name);
+		kfree(param->node_name);
+		kfree(param);
+	}
+}
+
+static inline void free_dfs_info_array(struct dfs_info3_param *param,
+				       int number_of_items)
+{
+	int i;
+	if ((number_of_items == 0) || (param == NULL))
+		return;
+	for (i = 0; i < number_of_items; i++) {
+		kfree(param[i].path_name);
+		kfree(param[i].node_name);
+	}
+	kfree(param);
+}
+
 #define   MID_FREE 0
 #define   MID_REQUEST_ALLOCATED 1
 #define   MID_REQUEST_SUBMITTED 2
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 8350eec..b7402ba 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -142,8 +142,8 @@ extern int CIFSSMBUnixQPathInfo(const int xid,
 
 extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
 			const unsigned char *searchName,
-			unsigned char **targetUNCs,
-			unsigned int *number_of_UNC_in_array,
+			struct dfs_info3_param **targetNode,
+			unsigned int *number_of_Nodes_in_array,
 			const struct nls_table *nls_codepage, int remap);
 
 extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
@@ -153,7 +153,7 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 			const char *old_path,
 			const struct nls_table *nls_codepage,
 			unsigned int *pnum_referrals,
-			unsigned char **preferrals,
+			struct dfs_info3_param **preferrals,
 			int remap);
 extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
 				 struct super_block *sb, struct smb_vol *vol);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 9e8a6be..f4bbb57 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3879,8 +3879,8 @@ GetInodeNumOut:
 int
 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
 		const unsigned char *searchName,
-		unsigned char **targetUNCs,
-		unsigned int *number_of_UNC_in_array,
+		struct dfs_info3_param **targetNode,
+		unsigned int *number_of_Nodes_in_array,
 		const struct nls_table *nls_codepage, int remap)
 {
 /* TRANS2_GET_DFS_REFERRAL */
@@ -3892,9 +3892,9 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
 	int name_len;
 	unsigned int i;
 	char *temp;
-	__u16 params, byte_count;
-	*number_of_UNC_in_array = 0;
-	*targetUNCs = NULL;
+	__u16 params, byte_count, data_offset, data_count;
+	*number_of_Nodes_in_array = 0;
+	*targetNode = NULL;
 
 	cFYI(1, ("In GetDFSRefer the path %s", searchName));
 	if (ses == NULL)
@@ -3963,100 +3963,150 @@ getDFSRetry:
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 	if (rc) {
 		cFYI(1, ("Send error in GetDFSRefer = %d", rc));
-	} else {		/* decode response */
-/* BB Add logic to parse referrals here */
-		rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+		goto GetDFSRefExit;
+	}
 
-		/* BB Also check if enough total bytes returned? */
-		if (rc || (pSMBr->ByteCount < 17))
-			rc = -EIO;      /* bad smb */
-		else {
-			__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
-			__u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
+	/* decode response */
+	rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
-			cFYI(1,
-			    ("Decoding GetDFSRefer response BCC: %d  Offset %d",
-			      pSMBr->ByteCount, data_offset));
-			referrals =
-			    (struct dfs_referral_level_3 *)
-					(8 /* sizeof start of data block */ +
-					data_offset +
-					(char *) &pSMBr->hdr.Protocol);
-			cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
-				"for referral one refer size: 0x%x srv "
-				"type: 0x%x refer flags: 0x%x ttl: 0x%x",
+	/* BB Also check if enough total bytes returned? */
+	if (rc || (pSMBr->ByteCount < 17)) {
+		rc = -EIO;      /* bad smb */
+		goto GetDFSRefExit;
+	}
+
+	data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+	data_count = le16_to_cpu(pSMBr->t2.DataCount);
+
+	cFYI(1,
+			("Decoding GetDFSRefer response BCC: %d  Offset %d",
+			 pSMBr->ByteCount, data_offset));
+	/* BB This field is actually two bytes in from start of
+	   data block so we could do safety check that DataBlock
+	   begins at address of pSMBr->NumberOfReferrals */
+	*number_of_Nodes_in_array =
+		le16_to_cpu(pSMBr->NumberOfReferrals);
+
+	/* BB Fix below so can return more than one referral */
+	if (*number_of_Nodes_in_array > 1)
+		*number_of_Nodes_in_array = 1;
+
+	*targetNode = kmalloc(sizeof(struct dfs_info3_param) +
+			(*number_of_Nodes_in_array), GFP_KERNEL);
+	if (*targetNode == NULL) {
+		*number_of_Nodes_in_array = 0;
+		rc = -ENOMEM;
+		goto GetDFSRefExit;
+	}
+	for (i = 0; i < *number_of_Nodes_in_array; i++)
+		init_dfs_info_param(targetNode[i]);
+
+	/* copy the refs info */
+	referrals =
+		(struct dfs_referral_level_3 *)
+		(8 /* sizeof data hdr */ +
+		 data_offset +
+		 (char *) &pSMBr->hdr.Protocol);
+
+	cFYI(1, ("num_referrals: %d dfs flags: 0x%x",
 				le16_to_cpu(pSMBr->NumberOfReferrals),
-				le16_to_cpu(pSMBr->DFSFlags),
+				le16_to_cpu(pSMBr->DFSFlags)));
+	cFYI(1, ("1st ref (size: 0x%x srv type: 0x%x flags: 0x%x ttl: 0x%x)",
 				le16_to_cpu(referrals->ReferralSize),
 				le16_to_cpu(referrals->ServerType),
 				le16_to_cpu(referrals->ReferralFlags),
 				le16_to_cpu(referrals->TimeToLive)));
-			/* BB This field is actually two bytes in from start of
-			   data block so we could do safety check that DataBlock
-			   begins at address of pSMBr->NumberOfReferrals */
-			*number_of_UNC_in_array =
-					le16_to_cpu(pSMBr->NumberOfReferrals);
-
-			/* BB Fix below so can return more than one referral */
-			if (*number_of_UNC_in_array > 1)
-				*number_of_UNC_in_array = 1;
-
-			/* get the length of the strings describing refs */
-			name_len = 0;
-			for (i = 0; i < *number_of_UNC_in_array; i++) {
-				/* make sure that DfsPathOffset not past end */
-				__u16 offset =
-					le16_to_cpu(referrals->DfsPathOffset);
-				if (offset > data_count) {
-					/* if invalid referral, stop here and do
-					not try to copy any more */
-					*number_of_UNC_in_array = i;
-					break;
-				}
-				temp = ((char *)referrals) + offset;
 
-				if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
-					name_len += UniStrnlen((wchar_t *)temp,
-								data_count);
-				} else {
-					name_len += strnlen(temp, data_count);
-				}
-				referrals++;
-				/* BB add check that referral pointer does
-				   not fall off end PDU */
+	for (i = 0; i < *number_of_Nodes_in_array; i++) {
+		/* copy answer and refferal attr */
+		(*targetNode)[i].flags =
+			le16_to_cpu(pSMBr->DFSFlags);
+		(*targetNode)[i].PathConsumed =
+			le16_to_cpu(pSMBr->PathConsumed);
+		(*targetNode)[i].server_type =
+			le16_to_cpu(referrals->ServerType);
+		(*targetNode)[i].ref_flag =
+			le16_to_cpu(referrals->ReferralFlags);
+
+		/* copy ref path name */
+		temp = ((char *)referrals)
+			+ le16_to_cpu(referrals->DfsPathOffset);
+		if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+			int plen;
+			plen = UniStrnlen((wchar_t *)temp,
+				data_count - (temp - ((char *)referrals)));
+			(*targetNode)[i].path_name = kmalloc(plen + 2,
+					GFP_KERNEL);
+			if ((*targetNode)[i].path_name == NULL) {
+				free_dfs_info_array(*targetNode,
+						*number_of_Nodes_in_array);
+				*targetNode = NULL;
+				*number_of_Nodes_in_array = 0;
+				rc = -ENOMEM;
+				goto GetDFSRefExit;
 			}
-			/* BB add check for name_len bigger than bcc */
-			*targetUNCs =
-				kmalloc(name_len+1+(*number_of_UNC_in_array),
+			cifs_strfromUCS_le((*targetNode)[i].path_name,
+					(__le16 *) temp, plen, nls_codepage);
+			(*targetNode)[i].path_name[plen] = 0;
+		} else {
+			int plen;
+			plen = strnlen(temp,
+				data_count - (temp - ((char *)referrals)));
+			(*targetNode)[i].path_name = kmalloc(plen + 2,
 					GFP_KERNEL);
-			if (*targetUNCs == NULL) {
+			if (*targetNode == NULL) {
+				free_dfs_info_array(*targetNode,
+						*number_of_Nodes_in_array);
+				*targetNode = NULL;
+				*number_of_Nodes_in_array = 0;
 				rc = -ENOMEM;
 				goto GetDFSRefExit;
 			}
-			/* copy the ref strings */
-			referrals = (struct dfs_referral_level_3 *)
-					(8 /* sizeof data hdr */ + data_offset +
-					(char *) &pSMBr->hdr.Protocol);
-
-			for (i = 0; i < *number_of_UNC_in_array; i++) {
-				temp = ((char *)referrals) +
-					  le16_to_cpu(referrals->DfsPathOffset);
-				if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
-					cifs_strfromUCS_le(*targetUNCs,
-							  (__le16 *) temp,
-							  name_len,
-							  nls_codepage);
-				} else {
-					strncpy(*targetUNCs, temp, name_len);
-				}
-				/*  BB update target_uncs pointers */
-				referrals++;
+			strncpy((*targetNode)[i].path_name, temp, plen);
+			(*targetNode)[i].path_name[plen] = 0;
+		}
+
+		/* copy node path name */
+		temp = ((char *)referrals) +
+			le16_to_cpu(referrals->NetworkAddressOffset);
+		if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+			int plen;
+			plen = UniStrnlen((wchar_t *)temp,
+				data_count - (temp - ((char *)referrals)));
+			(*targetNode)[i].node_name = kmalloc(plen + 2,
+					GFP_KERNEL);
+			if ((*targetNode)[i].node_name == NULL) {
+				free_dfs_info_array(*targetNode,
+						*number_of_Nodes_in_array);
+				*targetNode = NULL;
+				*number_of_Nodes_in_array = 0;
+				rc = -ENOMEM;
+				goto GetDFSRefExit;
+			}
+			cifs_strfromUCS_le((*targetNode)[i].node_name,
+					(__le16 *) temp, plen, nls_codepage);
+			(*targetNode)[i].node_name[plen] = 0;
+		} else {
+			int plen;
+			plen = strnlen(temp,
+				data_count - (temp - ((char *)referrals)));
+			(*targetNode)[i].node_name = kmalloc(plen + 2,
+					GFP_KERNEL);
+			if (*targetNode == NULL) {
+				free_dfs_info_array(*targetNode,
+						*number_of_Nodes_in_array);
+				*targetNode = NULL;
+				*number_of_Nodes_in_array = 0;
+				rc = -ENOMEM;
+				goto GetDFSRefExit;
 			}
-			temp = *targetUNCs;
-			temp[name_len] = 0;
+			strncpy((*targetNode)[i].node_name, temp, plen);
+			(*targetNode)[i].node_name[plen] = 0;
 		}
 
+		referrals++;
 	}
+
 GetDFSRefExit:
 	if (pSMB)
 		cifs_buf_release(pSMB);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index fd9147c..8b22160 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1405,31 +1405,35 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
 	return NULL;
 }
 
+/* BB: Probably we do not need this function any more.
+ * Anyway it never worked. May be one day we well need it.
+ */
 int
 connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 		    const char *old_path, const struct nls_table *nls_codepage,
 		    int remap)
 {
+	/*
 	unsigned char *referrals = NULL;
 	unsigned int num_referrals;
 	int rc = 0;
 
 	rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
 			&num_referrals, &referrals, remap);
-
+	*/
 	/* BB Add in code to: if valid refrl, if not ip address contact
 		the helper that resolves tcp names, mount to it, try to
 		tcon to it unmount it if fail */
-
+	/*
 	kfree(referrals);
-
-	return rc;
+	*/
+	return -ENOSYS;
 }
 
 int
 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
 	     const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
-	     unsigned char **preferrals, int remap)
+	     struct dfs_info3_param **preferrals, int remap)
 {
 	char *temp_unc;
 	int rc = 0;
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 11f2657..c30619a 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -307,12 +307,15 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
 						MAX_TREE_SIZE);
 					strncat(tmp_path, full_path,
 						MAX_PATHCONF);
+					rc = -ENOSYS;
+					/*
 					rc = get_dfs_path(xid, pTcon->ses,
 						tmp_path,
 						cifs_sb->local_nls,
 						&num_referrals, &referrals,
 						cifs_sb->mnt_cifs_flags &
 						    CIFS_MOUNT_MAP_SPECIAL_CHR);
+					*/
 					cFYI(1, ("Get DFS for %s rc = %d ",
 						tmp_path, rc));
 					if ((num_referrals == 0) && (rc == 0))
-- 
1.5.3.7






More information about the linux-cifs-client mailing list