>From 490ed5e40713206bf3011880b03cd9f5766b5467 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Fri, 15 Feb 2008 19:31:42 +0300 Subject: [PATCH] DFS patch that connects inode with dfs handling ops if it is DFS junction point. 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 --- fs/cifs/cifs_dfs_ref.c | 10 +++++ fs/cifs/cifsfs.h | 11 ++++++ fs/cifs/inode.c | 93 +++++++++++++++++++++--------------------------- 3 files changed, 62 insertions(+), 52 deletions(-) diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 413ee23..3161986 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -29,6 +29,16 @@ LIST_HEAD(cifs_dfs_automount_list); * DFS functions */ +void cifs_dfs_ref_inode_op_fixup(int is_remote, struct inode *inode) +{ + if (is_remote) { + inode->i_op = &cifs_dfs_referral_inode_operations; + } else { + inode->i_op = &cifs_dir_inode_ops; + inode->i_fop = &cifs_dir_ops; + } +} + void dfs_shrink_umount_helper(struct vfsmount *vfsmnt) { mark_mounts_for_expiry(&cifs_dfs_automount_list); diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 195b14d..d693e2d 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -91,6 +91,17 @@ extern int cifs_dir_notify(struct file *, unsigned long arg); extern struct dentry_operations cifs_dentry_ops; extern struct dentry_operations cifs_ci_dentry_ops; +#ifdef CONFIG_CIFS_DFS_UPCALL +extern void cifs_dfs_ref_inode_op_fixup(int is_remote, struct inode *inode); +#else +static inline void cifs_dfs_ref_inode_op_fixup(int is_remote, + struct inode *inode) +{ + inode->i_op = &cifs_dir_inode_ops; + inode->i_fop = &cifs_dir_ops; +} +#endif /* DFS_UPCALL */ + /* Functions related to symlinks */ extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); extern void cifs_put_link(struct dentry *direntry, diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 6020add..79e61c5 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -37,7 +37,7 @@ 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; + int is_remote = 0; pTcon = cifs_sb->tcon; cFYI(1, ("Getting info on %s", search_path)); @@ -48,30 +48,10 @@ 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; - } + /* BB: we need to revise code here + * and do it as in cifs_get_inode_info + * now it will return error -EREMOTE in case of dfs*/ + return rc; } else { struct cifsInodeInfo *cifsInfo; __u32 type = le32_to_cpu(findData.Type); @@ -200,8 +180,7 @@ 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")); - inode->i_op = &cifs_dir_inode_ops; - inode->i_fop = &cifs_dir_ops; + cifs_dfs_ref_inode_op_fixup(is_remote, inode); } else if (S_ISLNK(inode->i_mode)) { cFYI(1, ("Symbolic Link inode")); inode->i_op = &cifs_symlink_inode_ops; @@ -326,8 +305,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 +322,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 +370,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; @@ -567,8 +557,7 @@ 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")); - inode->i_op = &cifs_dir_inode_ops; - inode->i_fop = &cifs_dir_ops; + cifs_dfs_ref_inode_op_fixup(is_remote, inode); } else if (S_ISLNK(inode->i_mode)) { cFYI(1, ("Symbolic Link inode")); inode->i_op = &cifs_symlink_inode_ops; -- 1.5.3.7