[CIFS] DFS patch that connects inode with dfs handling ops

if DFS junction point

Signed-off-by: Igor Mammedov <niallain@gmail.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Igor Mammedov 2008-03-09 03:44:18 +00:00 committed by Steve French
parent 84c6f6046c
commit 7962670e64

View File

@ -30,7 +30,7 @@
#include "cifs_fs_sb.h"
static void cifs_set_ops(struct inode *inode)
static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@ -57,8 +57,12 @@ static void cifs_set_ops(struct inode *inode)
inode->i_data.a_ops = &cifs_addr_ops;
break;
case S_IFDIR:
inode->i_op = &cifs_dir_inode_ops;
inode->i_fop = &cifs_dir_ops;
if (is_dfs_referral) {
inode->i_op = &cifs_dfs_referral_inode_operations;
} else {
inode->i_op = &cifs_dir_inode_ops;
inode->i_fop = &cifs_dir_ops;
}
break;
case S_IFLNK:
inode->i_op = &cifs_symlink_inode_ops;
@ -153,6 +157,30 @@ static void cifs_unix_info_to_inode(struct inode *inode,
spin_unlock(&inode->i_lock);
}
static const unsigned char *cifs_get_search_path(struct cifsTconInfo *pTcon,
const char *search_path)
{
int tree_len;
int path_len;
char *tmp_path;
if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS))
return search_path;
/* use full path name for working with DFS */
tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1);
path_len = strnlen(search_path, MAX_PATHCONF);
tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL);
if (tmp_path == NULL)
return search_path;
strncpy(tmp_path, pTcon->treeName, tree_len);
strncpy(tmp_path+tree_len, search_path, path_len);
tmp_path[tree_len+path_len] = 0;
return tmp_path;
}
int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path, struct super_block *sb, int xid)
{
@ -161,41 +189,28 @@ 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;
const unsigned char *full_path;
bool is_dfs_referral = false;
pTcon = cifs_sb->tcon;
cFYI(1, ("Getting info on %s", search_path));
full_path = cifs_get_search_path(pTcon, search_path);
try_again_CIFSSMBUnixQPathInfo:
/* could have done a find first instead but this returns more info */
rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
/* 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;
if (rc == -EREMOTE && !is_dfs_referral) {
is_dfs_referral = true;
full_path = search_path;
goto try_again_CIFSSMBUnixQPathInfo;
}
goto cgiiu_exit;
} else {
struct cifsInodeInfo *cifsInfo;
__u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
@ -204,8 +219,10 @@ int cifs_get_inode_info_unix(struct inode **pinode,
/* get new inode */
if (*pinode == NULL) {
*pinode = new_inode(sb);
if (*pinode == NULL)
return -ENOMEM;
if (*pinode == NULL) {
rc = -ENOMEM;
goto cgiiu_exit;
}
/* Is an i_ino of zero legal? */
/* Are there sanity checks we can use to ensure that
the server is really filling in that field? */
@ -237,8 +254,11 @@ int cifs_get_inode_info_unix(struct inode **pinode,
(unsigned long) inode->i_size,
(unsigned long long)inode->i_blocks));
cifs_set_ops(inode);
cifs_set_ops(inode, is_dfs_referral);
}
cgiiu_exit:
if (full_path != search_path)
kfree(full_path);
return rc;
}
@ -353,9 +373,10 @@ 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;
const unsigned char *full_path = NULL;
char *buf = NULL;
int adjustTZ = FALSE;
bool is_dfs_referral = false;
pTcon = cifs_sb->tcon;
cFYI(1, ("Getting info on %s", search_path));
@ -373,8 +394,12 @@ int cifs_get_inode_info(struct inode **pinode,
if (buf == NULL)
return -ENOMEM;
pfindData = (FILE_ALL_INFO *)buf;
full_path = cifs_get_search_path(pTcon, search_path);
try_again_CIFSSMBQPathInfo:
/* 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);
@ -382,7 +407,7 @@ int cifs_get_inode_info(struct inode **pinode,
when server claims no NT SMB support and the above call
failed at least once - set flag in tcon or mount */
if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
rc = SMBQueryInformation(xid, pTcon, search_path,
rc = SMBQueryInformation(xid, pTcon, full_path,
pfindData, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
@ -391,31 +416,12 @@ 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. */
} else if (rc) {
kfree(buf);
return rc;
if (rc == -EREMOTE && !is_dfs_referral) {
is_dfs_referral = true;
full_path = search_path;
goto try_again_CIFSSMBQPathInfo;
}
goto cgii_exit;
} else {
struct cifsInodeInfo *cifsInfo;
__u32 attr = le32_to_cpu(pfindData->Attributes);
@ -424,8 +430,8 @@ int cifs_get_inode_info(struct inode **pinode,
if (*pinode == NULL) {
*pinode = new_inode(sb);
if (*pinode == NULL) {
kfree(buf);
return -ENOMEM;
rc = -ENOMEM;
goto cgii_exit;
}
/* Is an i_ino of zero legal? Can we use that to check
if the server supports returning inode numbers? Are
@ -573,8 +579,11 @@ int cifs_get_inode_info(struct inode **pinode,
atomic_set(&cifsInfo->inUse, 1);
}
cifs_set_ops(inode);
cifs_set_ops(inode, is_dfs_referral);
}
cgii_exit:
if (full_path != search_path)
kfree(full_path);
kfree(buf);
return rc;
}
@ -804,7 +813,7 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
local_size = tmp_inode->i_size;
cifs_unix_info_to_inode(tmp_inode, pData, 1);
cifs_set_ops(tmp_inode);
cifs_set_ops(tmp_inode, false);
if (!S_ISREG(tmp_inode->i_mode))
return;