[linux-cifs-client] [DFS support patchset: ] [5/5]: Provides mapping of inode->i_op to cifs_dfs_referral_inode_operations if remote path is DFS junction point.

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


	DFS junction point is detected by EREMOTE error from
	CIFSSMBQPathInfo. Then we need to request server again,
	this time with full path name so we could get correct
	info for this inode.

	It is final DFS patch that gets all patchset working
	and it depends on all previous DFS patches.

Signed-off-by: Igor Mammedov <niallain at gmail.com>
---
 fs/cifs/inode.c |  110 ++++++++++++++++++++++++++++++------------------------
 1 files changed, 61 insertions(+), 49 deletions(-)

diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index e915eb1..1e8fddd 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -28,6 +28,7 @@
 #include "cifsproto.h"
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
+#include "cifs_dfs_ref.h"
 
 int cifs_get_inode_info_unix(struct inode **pinode,
 	const unsigned char *search_path, struct super_block *sb, int xid)
@@ -37,8 +38,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 	struct cifsTconInfo *pTcon;
 	struct inode *inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	char *tmp_path;
-
+#ifdef CONFIG_CIFS_DFS_UPCALL
+	int is_remote = 0;
+#endif
 	pTcon = cifs_sb->tcon;
 	cFYI(1, ("Getting info on %s", search_path));
 	/* could have done a find first instead but this returns more info */
@@ -48,30 +50,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 /*	dump_mem("\nUnixQPathInfo return data", &findData,
 		 sizeof(findData)); */
 	if (rc) {
-		if (rc == -EREMOTE) {
-			tmp_path =
-			    kmalloc(strnlen(pTcon->treeName,
-					    MAX_TREE_SIZE + 1) +
-				    strnlen(search_path, MAX_PATHCONF) + 1,
-				    GFP_KERNEL);
-			if (tmp_path == NULL) {
-				return -ENOMEM;
-			}
-			/* have to skip first of the double backslash of
-			   UNC name */
-			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
-			strncat(tmp_path, search_path, MAX_PATHCONF);
-			rc = connect_to_dfs_path(xid, pTcon->ses,
-						 /* treename + */ tmp_path,
-						 cifs_sb->local_nls,
-						 cifs_sb->mnt_cifs_flags &
-						    CIFS_MOUNT_MAP_SPECIAL_CHR);
-			kfree(tmp_path);
-
-			/* BB fix up inode etc. */
-		} else if (rc) {
-			return rc;
-		}
+				return rc;
 	} else {
 		struct cifsInodeInfo *cifsInfo;
 		__u32 type = le32_to_cpu(findData.Type);
@@ -200,8 +179,19 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 				inode->i_data.a_ops = &cifs_addr_ops;
 		} else if (S_ISDIR(inode->i_mode)) {
 			cFYI(1, ("Directory inode"));
+#ifdef CONFIG_CIFS_DFS_UPCALL
+			if (is_remote) {
+				inode->i_op =
+					&cifs_dfs_referral_inode_operations;
+				inode->i_fop = NULL;
+			} else {
+				inode->i_op = &cifs_dir_inode_ops;
+				inode->i_fop = &cifs_dir_ops;
+			}
+#else
 			inode->i_op = &cifs_dir_inode_ops;
 			inode->i_fop = &cifs_dir_ops;
+#endif
 		} else if (S_ISLNK(inode->i_mode)) {
 			cFYI(1, ("Symbolic Link inode"));
 			inode->i_op = &cifs_symlink_inode_ops;
@@ -326,8 +316,9 @@ int cifs_get_inode_info(struct inode **pinode,
 	struct cifsTconInfo *pTcon;
 	struct inode *inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	char *tmp_path;
+	char *tmp_path = NULL;
 	char *buf = NULL;
+	int is_remote = 0;
 	int adjustTZ = FALSE;
 
 	pTcon = cifs_sb->tcon;
@@ -342,12 +333,38 @@ int cifs_get_inode_info(struct inode **pinode,
 
 	/* if file info not passed in then get it from server */
 	if (pfindData == NULL) {
+		int l_max_len;
+		const char *full_path;
+try_again_CIFSSMBQPathInfo:
+
 		buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
 		if (buf == NULL)
 			return -ENOMEM;
 		pfindData = (FILE_ALL_INFO *)buf;
+
+		cFYI(1, ("%s: pTcon->Flags: 0x%x", __FUNCTION__, pTcon->Flags));
+		if ((!is_remote) && (pTcon->Flags & 0x2)) {
+			/* use full path name for working with DFS */
+			l_max_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1)
+				+ strnlen(search_path, MAX_PATHCONF) + 1;
+			kfree(tmp_path);
+			tmp_path = kmalloc(l_max_len, GFP_KERNEL);
+			if (tmp_path == NULL) {
+				kfree(buf);
+				return -ENOMEM;
+			}
+			strncpy(tmp_path, pTcon->treeName, l_max_len);
+			strcat(tmp_path, search_path);
+			tmp_path[l_max_len-1] = 0;
+			full_path = tmp_path;
+		} else {
+			full_path = search_path;
+		}
+
+		cFYI(1, ("%s: query server with full path: '%s'",
+					__FUNCTION__, full_path));
 		/* could do find first instead but this returns more info */
-		rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
+		rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
 			      0 /* not legacy */,
 			      cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
 				CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -364,27 +381,11 @@ int cifs_get_inode_info(struct inode **pinode,
 	}
 	/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
 	if (rc) {
-		if (rc == -EREMOTE) {
-			tmp_path =
-			    kmalloc(strnlen
-				    (pTcon->treeName,
-				     MAX_TREE_SIZE + 1) +
-				    strnlen(search_path, MAX_PATHCONF) + 1,
-				    GFP_KERNEL);
-			if (tmp_path == NULL) {
-				kfree(buf);
-				return -ENOMEM;
-			}
-
-			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
-			strncat(tmp_path, search_path, MAX_PATHCONF);
-			rc = connect_to_dfs_path(xid, pTcon->ses,
-						 /* treename + */ tmp_path,
-						 cifs_sb->local_nls,
-						 cifs_sb->mnt_cifs_flags &
-						   CIFS_MOUNT_MAP_SPECIAL_CHR);
-			kfree(tmp_path);
-			/* BB fix up inode etc. */
+		if ((rc == -EREMOTE) && (!is_remote)) {
+			is_remote = 1;
+			kfree(buf);
+			buf = NULL;
+			goto try_again_CIFSSMBQPathInfo;
 		} else if (rc) {
 			kfree(buf);
 			return rc;
@@ -566,8 +567,19 @@ int cifs_get_inode_info(struct inode **pinode,
 				inode->i_data.a_ops = &cifs_addr_ops;
 		} else if (S_ISDIR(inode->i_mode)) {
 			cFYI(1, ("Directory inode"));
+#ifdef CONFIG_CIFS_DFS_UPCALL
+			if (is_remote) {
+				inode->i_op =
+					&cifs_dfs_referral_inode_operations;
+				inode->i_fop = NULL;
+			} else {
+				inode->i_op = &cifs_dir_inode_ops;
+				inode->i_fop = &cifs_dir_ops;
+			}
+#else
 			inode->i_op = &cifs_dir_inode_ops;
 			inode->i_fop = &cifs_dir_ops;
+#endif
 		} else if (S_ISLNK(inode->i_mode)) {
 			cFYI(1, ("Symbolic Link inode"));
 			inode->i_op = &cifs_symlink_inode_ops;
-- 
1.5.3.7






More information about the linux-cifs-client mailing list