From patchwork Thu Nov 15 14:20:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Aur=C3=A9lien_Aptel?= X-Patchwork-Id: 998368 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-cifs-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42wk8V4SVsz9s3q for ; Fri, 16 Nov 2018 01:22:18 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387839AbeKPAaT (ORCPT ); Thu, 15 Nov 2018 19:30:19 -0500 Received: from mx2.suse.de ([195.135.220.15]:42804 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732953AbeKPAaT (ORCPT ); Thu, 15 Nov 2018 19:30:19 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 6972FAD70; Thu, 15 Nov 2018 14:22:14 +0000 (UTC) From: Aurelien Aptel To: linux-cifs@vger.kernel.org Cc: smfrench@gmail.com, Paulo Alcantara , Paulo Alcantara , Aurelien Aptel Subject: [PATCH v1 09/14] cifs: Make use of DFS cache to get new DFS referrals Date: Thu, 15 Nov 2018 15:20:58 +0100 Message-Id: <20181115142103.24617-10-aaptel@suse.com> X-Mailer: git-send-email 2.13.7 In-Reply-To: <20181115142103.24617-1-aaptel@suse.com> References: <20181115142103.24617-1-aaptel@suse.com> Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org From: Paulo Alcantara This patch will make use of DFS cache routines where appropriate and do not always request a new referral from server. Signed-off-by: Paulo Alcantara Signed-off-by: Aurelien Aptel --- fs/cifs/cifs_dfs_ref.c | 100 ++++++++++++++++++++++++++++++------------------- fs/cifs/cifsfs.c | 17 ++++++++- fs/cifs/cifsglob.h | 1 - fs/cifs/cifsproto.h | 19 +++++++--- fs/cifs/connect.c | 45 +++++++--------------- fs/cifs/smb1ops.c | 15 ++++---- 6 files changed, 113 insertions(+), 84 deletions(-) diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 7adbdf9eb137..6e6953f35db2 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -25,6 +25,7 @@ #include "dns_resolve.h" #include "cifs_debug.h" #include "cifs_unicode.h" +#include "dfs_cache.h" static LIST_HEAD(cifs_dfs_automount_list); @@ -285,16 +286,16 @@ static void dump_referral(const struct dfs_info3_param *ref) */ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) { - struct dfs_info3_param *referrals = NULL; - unsigned int num_referrals = 0; + struct dfs_info3_param referral = {0}; struct cifs_sb_info *cifs_sb; struct cifs_ses *ses; - char *full_path; + struct cifs_tcon *tcon; + char *full_path, *root_path; unsigned int xid; - int i; + int len; int rc; struct vfsmount *mnt; - struct tcon_link *tlink; + char sep; cifs_dbg(FYI, "in %s\n", __func__); BUG_ON(IS_ROOT(mntpt)); @@ -313,53 +314,76 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) goto cdda_exit; } + sep = CIFS_DIR_SEP(cifs_sb); + /* always use tree name prefix */ full_path = build_path_from_dentry_optional_prefix(mntpt, true); if (full_path == NULL) goto cdda_exit; - tlink = cifs_sb_tlink(cifs_sb); - if (IS_ERR(tlink)) { - mnt = ERR_CAST(tlink); + cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path); + + if (!cifs_sb_master_tlink(cifs_sb)) { + cifs_dbg(FYI, "%s: master tlink is NULL\n", __func__); + goto free_full_path; + } + + tcon = cifs_sb_master_tcon(cifs_sb); + if (!tcon) { + cifs_dbg(FYI, "%s: master tcon is NULL\n", __func__); goto free_full_path; } - ses = tlink_tcon(tlink)->ses; + root_path = kstrdup(tcon->treeName, GFP_KERNEL); + if (!root_path) { + mnt = ERR_PTR(-ENOMEM); + goto free_full_path; + } + cifs_dbg(FYI, "%s: root path: %s\n", __func__, root_path); + + ses = tcon->ses; xid = get_xid(); - rc = get_dfs_path(xid, ses, full_path + 1, cifs_sb->local_nls, - &num_referrals, &referrals, - cifs_remap(cifs_sb)); - free_xid(xid); - cifs_put_tlink(tlink); - - mnt = ERR_PTR(-ENOENT); - for (i = 0; i < num_referrals; i++) { - int len; - dump_referral(referrals + i); - /* connect to a node */ - len = strlen(referrals[i].node_name); - if (len < 2) { - cifs_dbg(VFS, "%s: Net Address path too short: %s\n", - __func__, referrals[i].node_name); - mnt = ERR_PTR(-EINVAL); - break; - } - mnt = cifs_dfs_do_refmount(mntpt, cifs_sb, - full_path, referrals + i); - cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n", - __func__, referrals[i].node_name, mnt); - if (!IS_ERR(mnt)) - goto success; + /* + * If DFS root has been expired, then unconditionally fetch it again to + * refresh DFS referral cache. + */ + rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), + root_path + 1, NULL, NULL); + if (!rc) { + rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, + cifs_remap(cifs_sb), full_path + 1, + &referral, NULL); } - /* no valid submounts were found; return error from get_dfs_path() by - * preference */ - if (rc != 0) + free_xid(xid); + + if (rc) { mnt = ERR_PTR(rc); + goto free_root_path; + } -success: - free_dfs_info_array(referrals, num_referrals); + dump_referral(&referral); + + len = strlen(referral.node_name); + if (len < 2) { + cifs_dbg(VFS, "%s: Net Address path too short: %s\n", + __func__, referral.node_name); + mnt = ERR_PTR(-EINVAL); + goto free_dfs_ref; + } + /* + * cifs_mount() will retry every available node server in case + * of failures. + */ + mnt = cifs_dfs_do_refmount(mntpt, cifs_sb, full_path, &referral); + cifs_dbg(FYI, "%s: cifs_dfs_do_refmount:%s , mnt:%p\n", __func__, + referral.node_name, mnt); + +free_dfs_ref: + free_dfs_info_param(&referral); +free_root_path: + kfree(root_path); free_full_path: kfree(full_path); cdda_exit: diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 865706edb307..62d48d486d8f 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -52,6 +52,9 @@ #include "cifs_spnego.h" #include "fscache.h" #include "smb2pdu.h" +#ifdef CONFIG_CIFS_DFS_UPCALL +#include "dfs_cache.h" +#endif int cifsFYI = 0; bool traceSMB; @@ -1494,10 +1497,15 @@ init_cifs(void) if (rc) goto out_destroy_mids; +#ifdef CONFIG_CIFS_DFS_UPCALL + rc = dfs_cache_init(); + if (rc) + goto out_destroy_request_bufs; +#endif /* CONFIG_CIFS_DFS_UPCALL */ #ifdef CONFIG_CIFS_UPCALL rc = init_cifs_spnego(); if (rc) - goto out_destroy_request_bufs; + goto out_destroy_dfs_cache; #endif /* CONFIG_CIFS_UPCALL */ #ifdef CONFIG_CIFS_ACL @@ -1525,6 +1533,10 @@ init_cifs(void) #endif #ifdef CONFIG_CIFS_UPCALL exit_cifs_spnego(); +out_destroy_dfs_cache: +#endif +#ifdef CONFIG_CIFS_DFS_UPCALL + dfs_cache_destroy(); out_destroy_request_bufs: #endif cifs_destroy_request_bufs(); @@ -1556,6 +1568,9 @@ exit_cifs(void) #ifdef CONFIG_CIFS_UPCALL exit_cifs_spnego(); #endif +#ifdef CONFIG_CIFS_DFS_UPCALL + dfs_cache_destroy(); +#endif cifs_destroy_request_bufs(); cifs_destroy_mids(); cifs_destroy_inodecache(); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index bd183ec17066..60c202bbcdfc 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1551,7 +1551,6 @@ static inline void free_dfs_info_param(struct dfs_info3_param *param) if (param) { kfree(param->path_name); kfree(param->node_name); - kfree(param); } } diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index efa5e36b3762..f277bc5a0c4e 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -22,6 +22,9 @@ #define _CIFSPROTO_H #include #include "trace.h" +#ifdef CONFIG_CIFS_DFS_UPCALL +#include "dfs_cache.h" +#endif struct statfs; struct smb_vol; @@ -294,11 +297,6 @@ extern int CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses, unsigned int *num_of_nodes, const struct nls_table *nls_codepage, int remap); -extern int get_dfs_path(const unsigned int xid, struct cifs_ses *ses, - const char *old_path, - const struct nls_table *nls_codepage, - unsigned int *num_referrals, - struct dfs_info3_param **referrals, int remap); extern int parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, unsigned int *num_of_nodes, struct dfs_info3_param **target_nodes, @@ -567,4 +565,15 @@ void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc); extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page, unsigned int *len, unsigned int *offset); +#ifdef CONFIG_CIFS_DFS_UPCALL +static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses, + const char *old_path, + const struct nls_table *nls_codepage, + struct dfs_info3_param *referral, int remap) +{ + return dfs_cache_find(xid, ses, nls_codepage, remap, old_path, + referral, NULL); +} +#endif + #endif /* _CIFSPROTO_H */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index b4fed69add86..92a7d028cb78 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -56,6 +56,10 @@ #include "fscache.h" #include "smb2proto.h" #include "smbdirect.h" +#include "dns_resolve.h" +#ifdef CONFIG_CIFS_DFS_UPCALL +#include "dfs_cache.h" +#endif extern mempool_t *cifs_req_poolp; extern bool disable_legacy_dialects; @@ -3261,25 +3265,6 @@ cifs_match_super(struct super_block *sb, void *data) return rc; } -int -get_dfs_path(const unsigned int xid, struct cifs_ses *ses, const char *old_path, - const struct nls_table *nls_codepage, unsigned int *num_referrals, - struct dfs_info3_param **referrals, int remap) -{ - int rc = 0; - - if (!ses->server->ops->get_dfs_refer) - return -ENOSYS; - - *num_referrals = 0; - *referrals = NULL; - - rc = ses->server->ops->get_dfs_refer(xid, ses, old_path, - referrals, num_referrals, - nls_codepage, remap); - return rc; -} - #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key cifs_key[2]; static struct lock_class_key cifs_slock_key[2]; @@ -3930,8 +3915,9 @@ build_unc_path_to_root(const struct smb_vol *vol, return full_path; } -/* - * Perform a dfs referral query for a share and (optionally) prefix +/** + * expand_dfs_referral - Perform a dfs referral query and update the cifs_sb + * * * If a referral is found, cifs_sb->mountdata will be (re-)allocated * to a string containing updated options for the submount. Otherwise it @@ -3946,8 +3932,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, int check_prefix) { int rc; - unsigned int num_referrals = 0; - struct dfs_info3_param *referrals = NULL; + struct dfs_info3_param referral = {0}; char *full_path = NULL, *ref_path = NULL, *mdata = NULL; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) @@ -3960,17 +3945,15 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, /* For DFS paths, skip the first '\' of the UNC */ ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1; - rc = get_dfs_path(xid, ses, ref_path, cifs_sb->local_nls, - &num_referrals, &referrals, cifs_remap(cifs_sb)); - - if (!rc && num_referrals > 0) { + rc = dfs_cache_find(xid, ses, cifs_sb->local_nls, cifs_remap(cifs_sb), + ref_path, &referral, NULL); + if (!rc) { char *fake_devname = NULL; mdata = cifs_compose_mount_options(cifs_sb->mountdata, - full_path + 1, referrals, + full_path + 1, &referral, &fake_devname); - - free_dfs_info_array(referrals, num_referrals); + free_dfs_info_param(&referral); if (IS_ERR(mdata)) { rc = PTR_ERR(mdata); @@ -3978,7 +3961,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses, } else { cifs_cleanup_volume_info_contents(volume_info); rc = cifs_setup_volume_info(volume_info, mdata, - fake_devname, false); + fake_devname, false); } kfree(fake_devname); kfree(cifs_sb->mountdata); diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 378151e09e91..32a6c020478f 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -929,19 +929,18 @@ cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon, { #ifdef CONFIG_CIFS_DFS_UPCALL int rc; - unsigned int num_referrals = 0; - struct dfs_info3_param *referrals = NULL; + struct dfs_info3_param referral = {0}; - rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage, - &num_referrals, &referrals, 0); + rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage, &referral, + 0); - if (!rc && num_referrals > 0) { - *symlinkinfo = kstrndup(referrals->node_name, - strlen(referrals->node_name), + if (!rc) { + *symlinkinfo = kstrndup(referral.node_name, + strlen(referral.node_name), GFP_KERNEL); + free_dfs_info_param(&referral); if (!*symlinkinfo) rc = -ENOMEM; - free_dfs_info_array(referrals, num_referrals); } return rc; #else /* No DFS support */