forked from Minki/linux
[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:
parent
84c6f6046c
commit
7962670e64
133
fs/cifs/inode.c
133
fs/cifs/inode.c
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user