[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