All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
To: Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org>
Cc: linux-cifs <linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: Re: [PATCH v1 2/6] fs/cifs: implement get_dfs_refer for smb2
Date: Thu, 10 Nov 2016 16:42:59 -0800	[thread overview]
Message-ID: <CAKywueTPUsFvwPCxuRgha-e0x3R1a3kGsXT4QYkOQ5b8ApGm8g@mail.gmail.com> (raw)
In-Reply-To: <1478622806-19636-3-git-send-email-aaptel-IBi9RG/b67k@public.gmane.org>

2016-11-08 8:33 GMT-08:00 Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org>:
> Few issues with the current situation
>
> * the get_dfs_refer op is meant to be used from cifs thus the prototype
>   of the operation is not adapted for smb2:
>
>   - it passes a session as opposed to a tcon like other smb2 operations,
>     which means we have to find the corresponding tcon ourselves. see
>     new function find_session_tcon() which currently assumes the first one
>     is the right one.

I think it is ok since it matches the spec which suggests to find any
ses and tcon.

>
>   - it doesn't pass a cifs_sb so we cannot use the usual utf16
>     conversion function used in the rest of smb2 code

I suggest to pass cifs_sb to get_dfs_path() (instead of
cifs_remap(cifs_sb)) and then modify a get_dfs_refer() callback to
take cifs_sb as well. This let us use cifs_convert_path_to_utf16().

>
> * the DFS request has to be made on the IPC tcon and i'm not really sure
>   how to get to it since it doesnt seem to be part of the session tcon
>   list.

Should we probably add an extra param to SMB2_ioctl called ipc_tid? In
case when tcon passed to this function is NULL ipc_tid will be used in
a similar manner how it is done now for CIFS. Otherwise (if tcon is
not NULL) tcon is used as it is now.

>
> * the function that extracts the data from the responce is almost
>   entirely copied and adapted from the smb1 code. ideally they should be
>   merged.
>
> Signed-off-by: Aurelien Aptel <aaptel-IBi9RG/b67k@public.gmane.org>
> ---
>  fs/cifs/smb2ops.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 206 insertions(+)
>
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index 5d456eb..677579b 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -1093,6 +1093,212 @@ smb2_new_lease_key(struct cifs_fid *fid)
>         generate_random_uuid(fid->lease_key);
>  }
>
> +/*
> + * XXX: Return the tcon currently used in the session
> + */
> +static struct cifs_tcon *
> +find_session_tcon (struct cifs_ses *ses)
> +{
> +       struct cifs_tcon *tcon = NULL, *it;
> +       struct list_head *tmp;
> +       int i = 0;
> +
> +       spin_lock(&cifs_tcp_ses_lock);
> +       list_for_each(tmp, &ses->tcon_list) {
> +               it = list_entry(tmp, struct cifs_tcon, tcon_list);
> +               cifs_dbg(FYI, "XXX: [%d] tcon %p\n", i, it);
> +
> +               /* XXX: Assumes the first one is always the right one. */
> +               if (i == 0) {
> +                       tcon = it;
> +               }
> +               i++;
> +       }
> +       spin_unlock(&cifs_tcp_ses_lock);
> +
> +       if (!tcon)
> +               cifs_dbg(FYI, "XXX: cannot find our tcon\n");
> +       return tcon;
> +}
> +
> +/*
> + * XXX: Copied and adapted from parse_DFS_referrals in cifssmb.c
> + * TODO: extract logic in a SMB agnostic way
> + */
> +static int
> +smb2_parse_dfs_referrers_rsp(struct fsctl_get_dfs_referral_rsp *rsp, u32 rsp_size,
> +                            unsigned int *num_of_nodes,
> +                            struct dfs_info3_param **target_nodes,
> +                            const struct nls_table *nls_codepage, int remap,
> +                            const char *searchName)
> +{
> +       int i, rc = 0;
> +       char *data_end;
> +       bool is_unicode = true;
> +       struct dfs_referral_level_3 *ref;
> +
> +       *num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals);
> +
> +       if (*num_of_nodes < 1) {
> +               cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
> +                        *num_of_nodes);
> +               rc = -EINVAL;
> +               goto parse_DFS_referrals_exit;
> +       }
> +
> +       ref = (struct dfs_referral_level_3 *) &rsp->buffer[0];
> +       if (ref->VersionNumber != cpu_to_le16(3)) {
> +               cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
> +                        le16_to_cpu(ref->VersionNumber));
> +               rc = -EINVAL;
> +               goto parse_DFS_referrals_exit;
> +       }
> +
> +       /* get the upper boundary of the resp buffer */
> +       data_end = (char *)(&(rsp->PathConsumed)) + rsp_size;
> +
> +       cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
> +                *num_of_nodes, le32_to_cpu(rsp->ReferralHeaderFlags));
> +
> +       *target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
> +                               GFP_KERNEL);
> +       if (*target_nodes == NULL) {
> +               rc = -ENOMEM;
> +               goto parse_DFS_referrals_exit;
> +       }
> +
> +       /* collect necessary data from referrals */
> +       for (i = 0; i < *num_of_nodes; i++) {
> +               char *temp;
> +               int max_len;
> +               __le16 *tmp;
> +               struct dfs_info3_param *node = (*target_nodes)+i;
> +
> +               node->flags = le32_to_cpu(rsp->ReferralHeaderFlags);
> +               tmp = kmalloc(strlen(searchName)*2 + 2,
> +                             GFP_KERNEL);
> +               if (tmp == NULL) {
> +                       rc = -ENOMEM;
> +                       goto parse_DFS_referrals_exit;
> +               }
> +               cifsConvertToUTF16((__le16 *) tmp, searchName,
> +                                  PATH_MAX, nls_codepage, remap);
> +               node->path_consumed = cifs_utf16_bytes(tmp,
> +                                                      le16_to_cpu(rsp->PathConsumed),
> +                                                      nls_codepage);
> +               kfree(tmp);
> +
> +               node->server_type = le16_to_cpu(ref->ServerType);
> +               node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
> +
> +               /* copy DfsPath */
> +               temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
> +               max_len = data_end - temp;
> +               node->path_name = cifs_strndup_from_utf16(temp, max_len,
> +                                                         true /* is_unicode */, nls_codepage);
> +               if (!node->path_name) {
> +                       rc = -ENOMEM;
> +                       goto parse_DFS_referrals_exit;
> +               }
> +
> +               /* copy link target UNC */
> +               temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
> +               max_len = data_end - temp;
> +               node->node_name = cifs_strndup_from_utf16(temp, max_len,
> +                                               is_unicode, nls_codepage);
> +               if (!node->node_name) {
> +                       rc = -ENOMEM;
> +                       goto parse_DFS_referrals_exit;
> +               }
> +
> +               ref++;
> +       }
> +
> +parse_DFS_referrals_exit:
> +       if (rc) {
> +               free_dfs_info_array(*target_nodes, *num_of_nodes);
> +               *target_nodes = NULL;
> +               *num_of_nodes = 0;
> +       }
> +       return rc;
> +}
> +
> +
> +static int
> +smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
> +                  const char *search_name, struct dfs_info3_param **target_nodes,
> +                  unsigned int *num_of_nodes,
> +                  const struct nls_table *nls_codepage, int remap)
> +{
> +       int rc = -ENOSYS;
> +       __le16 *utf16_path = NULL;
> +       int utf16_path_len = 0;
> +       struct cifs_tcon *tcon;
> +       struct fsctl_get_dfs_referral_req *dfs_req = NULL;
> +       struct fsctl_get_dfs_referral_rsp *dfs_rsp = NULL;
> +       u32 dfs_req_size = 0, dfs_rsp_size = 0;
> +
> +       cifs_dbg(FYI, "XXX: In smb2_get_dfs_refer the path <%s> %d\n", search_name, (int)strlen(search_name));
> +
> +       /*
> +        * XXX: Find this session tcon. We shouldnt have to do this
> +        * proper solution would be to update get_dfs_refer op
> +        * prototype to pass it somehow.
> +        */
> +       tcon = find_session_tcon(ses);
> +       if (!tcon)
> +               goto out;
> +
> +       /*
> +        * XXX: Should we use use cifs_convert_path_to_utf16(full_path, cifs_sb) instead?
> +        * it needs cifs_sb superblock pointer which we don't have...
> +        */
> +
> +       utf16_path_len = strlen(search_name) * 2;
> +       utf16_path = kzalloc(utf16_path_len + 2, GFP_KERNEL);
> +       if (!utf16_path) {
> +               rc = -ENOMEM;
> +               goto out;
> +       }
> +
> +       cifsConvertToUTF16(utf16_path,
> +                          search_name, PATH_MAX, nls_codepage,
> +                          remap);
> +
> +       dfs_req_size = sizeof(*dfs_req) + utf16_path_len + 2;
> +       dfs_req = kzalloc(dfs_req_size, GFP_KERNEL);
> +       if (!dfs_req) {
> +               rc = -ENOMEM;
> +               goto out;
> +       }
> +
> +       /* Highest DFS referral version understood (actually the only supported one) */
> +       dfs_req->MaxReferralLevel = cpu_to_le16(DFS_VERSION);
> +       /* Path to resolve in an UTF-16 null-terminated string */
> +       memcpy(dfs_req->RequestFileName, utf16_path, utf16_path_len);
> +
> +       do {
> +               rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
> +                               FSCTL_DFS_GET_REFERRALS, true /* is_fsctl */,
> +                               (char *)dfs_req, dfs_req_size,
> +                               (char **)&dfs_rsp, &dfs_rsp_size);
> +               if (rc) {
> +                       cifs_dbg(FYI, "SMB2_ioctl error in smb2_get_dfs_refer rc=%d\n", rc);
> +                       goto out;
> +               }
> +
> +               rc = smb2_parse_dfs_referrers_rsp(dfs_rsp, dfs_rsp_size,
> +                                                 num_of_nodes, target_nodes,
> +                                                 nls_codepage, remap, search_name);
> +               kfree(dfs_rsp);
> +       } while (rc == -EAGAIN);
> +
> + out:
> +       kfree(utf16_path);
> +       kfree(dfs_req);
> +       return rc;
> +}
> +
>  #define SMB2_SYMLINK_STRUCT_SIZE \
>         (sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp))
>
> --
> 2.1.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Best regards,
Pavel Shilovsky

  parent reply	other threads:[~2016-11-11  0:42 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-08 16:33 [PATCH v1 0/6] Add support for DFS in smb2+ Aurelien Aptel
     [not found] ` <1478622806-19636-1-git-send-email-aaptel-IBi9RG/b67k@public.gmane.org>
2016-11-08 16:33   ` [PATCH v1 1/6] fs/cifs: add smb2 fsctl payloads for DFS resolving Aurelien Aptel
2016-11-08 16:33   ` [PATCH v1 2/6] fs/cifs: implement get_dfs_refer for smb2 Aurelien Aptel
     [not found]     ` <1478622806-19636-3-git-send-email-aaptel-IBi9RG/b67k@public.gmane.org>
2016-11-11  0:42       ` Pavel Shilovsky [this message]
2016-11-08 16:33   ` [PATCH v1 3/6] fs/cifs: always use ipc for DFS resolving ioctls Aurelien Aptel
     [not found]     ` <1478622806-19636-4-git-send-email-aaptel-IBi9RG/b67k@public.gmane.org>
2016-11-11  0:46       ` Pavel Shilovsky
2016-11-08 16:33   ` [PATCH v1 4/6] fs/cifs: add build_path_from_dentry_optional_prefix() Aurelien Aptel
2016-11-08 16:33   ` [PATCH v1 5/6] fs/cifs: always use tree name prefix for DFS resolving Aurelien Aptel
2016-11-08 16:33   ` [PATCH v1 6/6] fs/cifs: enable get_dfs_refer operation for smb2+ Aurelien Aptel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAKywueTPUsFvwPCxuRgha-e0x3R1a3kGsXT4QYkOQ5b8ApGm8g@mail.gmail.com \
    --to=piastryyy-re5jqeeqqe8avxtiumwx3w@public.gmane.org \
    --cc=aaptel-IBi9RG/b67k@public.gmane.org \
    --cc=linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.