forked from Minki/linux
cifs: Add DFS cache routines
* Add new dfs_cache.[ch] files * Add new /proc/fs/cifs/dfscache file - dump current cache when read - clear current cache when writing "0" to it * Add delayed_work to periodically refresh cache entries The new interface will be used for caching DFS referrals, as well as supporting client target failover. The DFS cache is a hashtable that maps UNC paths to cache entries. A cache entry contains: - the UNC path it is mapped on - how much the the UNC path the entry consumes - flags - a Time-To-Live after which the entry expires - a list of possible targets (linked lists of UNC paths) - a "hint target" pointing the last known working target or the first target if none were tried. This hint lets cifs.ko remember and try working targets first. * Looking for an entry in the cache is done with dfs_cache_find() - if no valid entries are found, a DFS query is made, stored in the cache and returned - the full target list can be copied and returned to avoid race conditions and looped on with the help with the dfs_cache_tgt_iterator * Updating the target hint to the next target is done with dfs_cache_update_tgthint() These functions have a dfs_cache_noreq_XXX() version that doesn't fetches referrals if no entries are found. These versions don't require the tcp/ses/tcon/cifs_sb parameters as a result. Expired entries cannot be used and since they have a pretty short TTL [1] in order for them to be useful for failover the DFS cache adds a delayed work called periodically to keep them fresh. Since we might not have available connections to issue the referral request when refreshing we need to store volume_info structs with credentials and other needed info to be able to connect to the right server. 1: Windows defaults: 5mn for domain-based referrals, 30mn for regular links Signed-off-by: Paulo Alcantara <palcantara@suse.de> Signed-off-by: Aurelien Aptel <aaptel@suse.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
e7b602f437
commit
54be1f6c1c
@ -17,7 +17,7 @@ cifs-$(CONFIG_CIFS_ACL) += cifsacl.o
|
||||
|
||||
cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o
|
||||
|
||||
cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
|
||||
cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o dfs_cache.o
|
||||
|
||||
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
|
||||
|
||||
|
@ -30,6 +30,9 @@
|
||||
#include "cifsproto.h"
|
||||
#include "cifs_debug.h"
|
||||
#include "cifsfs.h"
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
#include "dfs_cache.h"
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
#include "smbdirect.h"
|
||||
#endif
|
||||
@ -629,6 +632,11 @@ cifs_proc_init(void)
|
||||
&cifs_security_flags_proc_fops);
|
||||
proc_create("LookupCacheEnabled", 0644, proc_fs_cifs,
|
||||
&cifs_lookup_cache_proc_fops);
|
||||
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
proc_create("dfscache", 0644, proc_fs_cifs, &dfscache_proc_fops);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
proc_create("rdma_readwrite_threshold", 0644, proc_fs_cifs,
|
||||
&cifs_rdma_readwrite_threshold_proc_fops);
|
||||
@ -663,6 +671,10 @@ cifs_proc_clean(void)
|
||||
remove_proc_entry("SecurityFlags", proc_fs_cifs);
|
||||
remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
|
||||
remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
|
||||
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
remove_proc_entry("dfscache", proc_fs_cifs);
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
remove_proc_entry("rdma_readwrite_threshold", proc_fs_cifs);
|
||||
remove_proc_entry("smbd_max_frmr_depth", proc_fs_cifs);
|
||||
|
@ -1014,6 +1014,11 @@ struct cifs_tcon {
|
||||
struct list_head pending_opens; /* list of incomplete opens */
|
||||
struct cached_fid crfid; /* Cached root fid */
|
||||
/* BB add field for back pointer to sb struct(s)? */
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
char *dfs_path;
|
||||
int remap:2;
|
||||
struct list_head ulist; /* cache update list */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -527,6 +527,9 @@ extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
|
||||
extern void
|
||||
cifs_cleanup_volume_info_contents(struct smb_vol *volume_info);
|
||||
|
||||
extern struct TCP_Server_Info *
|
||||
cifs_find_tcp_session(struct smb_vol *vol);
|
||||
|
||||
void cifs_readdata_release(struct kref *refcount);
|
||||
int cifs_async_readv(struct cifs_readdata *rdata);
|
||||
int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
|
||||
|
@ -2295,7 +2295,7 @@ static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct TCP_Server_Info *
|
||||
struct TCP_Server_Info *
|
||||
cifs_find_tcp_session(struct smb_vol *vol)
|
||||
{
|
||||
struct TCP_Server_Info *server;
|
||||
|
1365
fs/cifs/dfs_cache.c
Normal file
1365
fs/cifs/dfs_cache.c
Normal file
File diff suppressed because it is too large
Load Diff
97
fs/cifs/dfs_cache.h
Normal file
97
fs/cifs/dfs_cache.h
Normal file
@ -0,0 +1,97 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* DFS referral cache routines
|
||||
*
|
||||
* Copyright (c) 2018 Paulo Alcantara <palcantara@suse.de>
|
||||
*/
|
||||
|
||||
#ifndef _CIFS_DFS_CACHE_H
|
||||
#define _CIFS_DFS_CACHE_H
|
||||
|
||||
#include <linux/nls.h>
|
||||
#include <linux/list.h>
|
||||
#include "cifsglob.h"
|
||||
|
||||
struct dfs_cache_tgt_list {
|
||||
int tl_numtgts;
|
||||
struct list_head tl_list;
|
||||
};
|
||||
|
||||
struct dfs_cache_tgt_iterator {
|
||||
char *it_name;
|
||||
struct list_head it_list;
|
||||
};
|
||||
|
||||
extern int dfs_cache_init(void);
|
||||
extern void dfs_cache_destroy(void);
|
||||
extern const struct file_operations dfscache_proc_fops;
|
||||
|
||||
extern int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
|
||||
const struct nls_table *nls_codepage, int remap,
|
||||
const char *path, struct dfs_info3_param *ref,
|
||||
struct dfs_cache_tgt_list *tgt_list);
|
||||
extern int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
|
||||
struct dfs_cache_tgt_list *tgt_list);
|
||||
extern int dfs_cache_update_tgthint(const unsigned int xid,
|
||||
struct cifs_ses *ses,
|
||||
const struct nls_table *nls_codepage,
|
||||
int remap, const char *path,
|
||||
const struct dfs_cache_tgt_iterator *it);
|
||||
extern int
|
||||
dfs_cache_noreq_update_tgthint(const char *path,
|
||||
const struct dfs_cache_tgt_iterator *it);
|
||||
extern int dfs_cache_get_tgt_referral(const char *path,
|
||||
const struct dfs_cache_tgt_iterator *it,
|
||||
struct dfs_info3_param *ref);
|
||||
extern int dfs_cache_add_vol(struct smb_vol *vol, const char *fullpath);
|
||||
extern int dfs_cache_update_vol(const char *fullpath,
|
||||
struct TCP_Server_Info *server);
|
||||
extern void dfs_cache_del_vol(const char *fullpath);
|
||||
|
||||
static inline struct dfs_cache_tgt_iterator *
|
||||
dfs_cache_get_next_tgt(struct dfs_cache_tgt_list *tl,
|
||||
struct dfs_cache_tgt_iterator *it)
|
||||
{
|
||||
if (!tl || list_empty(&tl->tl_list) || !it ||
|
||||
list_is_last(&it->it_list, &tl->tl_list))
|
||||
return NULL;
|
||||
return list_next_entry(it, it_list);
|
||||
}
|
||||
|
||||
static inline struct dfs_cache_tgt_iterator *
|
||||
dfs_cache_get_tgt_iterator(struct dfs_cache_tgt_list *tl)
|
||||
{
|
||||
if (!tl)
|
||||
return NULL;
|
||||
return list_first_entry_or_null(&tl->tl_list,
|
||||
struct dfs_cache_tgt_iterator,
|
||||
it_list);
|
||||
}
|
||||
|
||||
static inline void dfs_cache_free_tgts(struct dfs_cache_tgt_list *tl)
|
||||
{
|
||||
struct dfs_cache_tgt_iterator *it, *nit;
|
||||
|
||||
if (!tl || list_empty(&tl->tl_list))
|
||||
return;
|
||||
list_for_each_entry_safe(it, nit, &tl->tl_list, it_list) {
|
||||
list_del(&it->it_list);
|
||||
kfree(it->it_name);
|
||||
kfree(it);
|
||||
}
|
||||
tl->tl_numtgts = 0;
|
||||
}
|
||||
|
||||
static inline const char *
|
||||
dfs_cache_get_tgt_name(const struct dfs_cache_tgt_iterator *it)
|
||||
{
|
||||
return it ? it->it_name : NULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
dfs_cache_get_nr_tgts(const struct dfs_cache_tgt_list *tl)
|
||||
{
|
||||
return tl ? tl->tl_numtgts : 0;
|
||||
}
|
||||
|
||||
#endif /* _CIFS_DFS_CACHE_H */
|
Loading…
Reference in New Issue
Block a user