mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 08:02:07 +00:00
seven cifs/smb3 client fixes, all also for stable
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmQTfDQACgkQiiy9cAdy T1FXOQwAsqPc6ctQnl5V5UuZgfr0DZPurLgbrC35XgEYpHiopa4myZvl4Dc2DDTs f+TdLkd3fMBuopjOrO8RBN5JioruLeOLuTILlWwmcFqx9cXdM6aaMmGVAMU5JhhL ahgPjSgF2cft/zLBsiLb4N4T1WOctGRSpcAgX7AfQXqufBQ/auqMVldVcgPaMRD/ Si9R9qem8BXHTR8ZgBXrqzUKova0CN9JQICoV8yp9crK//0npHvgHkIIdflgxLwJ IE6D73MYo+xMrzlmV867kRO8xHeq03Er19WF73X1cGsVLJtsmxdbeFd8fXFIrDwf 4JRn5vvXiuHPIPqtMpdqcSU1/W1YP4R609cSketlpbqTWDvuGU1myN9tUqYYnYGv KyNSOQi+p4f/rC/8UdzCgbSAlt0wqoQJm/nV97uom5OWEjS3hgB8Tqh1akZPrwzc 7tXmJ4lETdUFSZCApmCAqHRwoG7WvnchCFxqNG85PCTybVuIEKDMjMkBl19pD8d1 ZfRHDulA =iLy+ -----END PGP SIGNATURE----- Merge tag '6.3-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull cifs client fixes from Steve French: "Seven cifs/smb3 client fixes, all also for stable: - four DFS fixes - multichannel reconnect fix - fix smb1 stats for cancel command - fix for set file size error path" * tag '6.3-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: use DFS root session instead of tcon ses cifs: return DFS root session id in DebugData cifs: fix use-after-free bug in refresh_cache_worker() cifs: set DFS root session in cifs_get_smb_ses() cifs: generate signkey for the channel that's reconnecting cifs: Fix smb2_set_path_size() cifs: Move the in_send statistic to __smb_send_rqst()
This commit is contained in:
commit
38e04b3e42
@ -420,6 +420,11 @@ skip_rdma:
|
||||
from_kuid(&init_user_ns, ses->linux_uid),
|
||||
from_kuid(&init_user_ns, ses->cred_uid));
|
||||
|
||||
if (ses->dfs_root_ses) {
|
||||
seq_printf(m, "\n\tDFS root session id: 0x%llx",
|
||||
ses->dfs_root_ses->Suid);
|
||||
}
|
||||
|
||||
spin_lock(&ses->chan_lock);
|
||||
if (CIFS_CHAN_NEEDS_RECONNECT(ses, 0))
|
||||
seq_puts(m, "\tPrimary channel: DISCONNECTED ");
|
||||
|
@ -179,6 +179,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
|
||||
tmp.source = full_path;
|
||||
tmp.leaf_fullpath = NULL;
|
||||
tmp.UNC = tmp.prepath = NULL;
|
||||
tmp.dfs_root_ses = NULL;
|
||||
|
||||
rc = smb3_fs_context_dup(ctx, &tmp);
|
||||
if (rc) {
|
||||
|
@ -61,8 +61,6 @@ struct cifs_sb_info {
|
||||
/* only used when CIFS_MOUNT_USE_PREFIX_PATH is set */
|
||||
char *prepath;
|
||||
|
||||
/* randomly generated 128-bit number for indexing dfs mount groups in referral cache */
|
||||
uuid_t dfs_mount_id;
|
||||
/*
|
||||
* Indicate whether serverino option was turned off later
|
||||
* (cifs_autodisable_serverino) in order to match new mounts.
|
||||
|
@ -1233,6 +1233,7 @@ struct cifs_tcon {
|
||||
/* BB add field for back pointer to sb struct(s)? */
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
struct list_head ulist; /* cache update list */
|
||||
struct list_head dfs_ses_list;
|
||||
#endif
|
||||
struct delayed_work query_interfaces; /* query interfaces workqueue job */
|
||||
};
|
||||
@ -1749,9 +1750,8 @@ struct cifs_mount_ctx {
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifs_ses *ses;
|
||||
struct cifs_tcon *tcon;
|
||||
struct cifs_ses *root_ses;
|
||||
uuid_t mount_id;
|
||||
char *origin_fullpath, *leaf_fullpath;
|
||||
struct list_head dfs_ses_list;
|
||||
};
|
||||
|
||||
static inline void free_dfs_info_param(struct dfs_info3_param *param)
|
||||
|
@ -2229,6 +2229,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
|
||||
* need to lock before changing something in the session.
|
||||
*/
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
ses->dfs_root_ses = ctx->dfs_root_ses;
|
||||
list_add(&ses->smb_ses_list, &server->smb_ses_list);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
@ -3407,7 +3408,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
|
||||
bool isdfs;
|
||||
int rc;
|
||||
|
||||
uuid_gen(&mnt_ctx.mount_id);
|
||||
INIT_LIST_HEAD(&mnt_ctx.dfs_ses_list);
|
||||
|
||||
rc = dfs_mount_share(&mnt_ctx, &isdfs);
|
||||
if (rc)
|
||||
goto error;
|
||||
@ -3427,7 +3429,6 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
|
||||
kfree(cifs_sb->prepath);
|
||||
cifs_sb->prepath = ctx->prepath;
|
||||
ctx->prepath = NULL;
|
||||
uuid_copy(&cifs_sb->dfs_mount_id, &mnt_ctx.mount_id);
|
||||
|
||||
out:
|
||||
cifs_try_adding_channels(cifs_sb, mnt_ctx.ses);
|
||||
@ -3439,7 +3440,7 @@ out:
|
||||
return rc;
|
||||
|
||||
error:
|
||||
dfs_cache_put_refsrv_sessions(&mnt_ctx.mount_id);
|
||||
dfs_put_root_smb_sessions(&mnt_ctx.dfs_ses_list);
|
||||
kfree(mnt_ctx.origin_fullpath);
|
||||
kfree(mnt_ctx.leaf_fullpath);
|
||||
cifs_mount_put_conns(&mnt_ctx);
|
||||
@ -3637,9 +3638,6 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
|
||||
spin_unlock(&cifs_sb->tlink_tree_lock);
|
||||
|
||||
kfree(cifs_sb->prepath);
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
dfs_cache_put_refsrv_sessions(&cifs_sb->dfs_mount_id);
|
||||
#endif
|
||||
call_rcu(&cifs_sb->rcu, delayed_free);
|
||||
}
|
||||
|
||||
|
@ -95,25 +95,31 @@ static int get_session(struct cifs_mount_ctx *mnt_ctx, const char *full_path)
|
||||
ctx->leaf_fullpath = (char *)full_path;
|
||||
rc = cifs_mount_get_session(mnt_ctx);
|
||||
ctx->leaf_fullpath = NULL;
|
||||
if (!rc) {
|
||||
struct cifs_ses *ses = mnt_ctx->ses;
|
||||
|
||||
mutex_lock(&ses->session_mutex);
|
||||
ses->dfs_root_ses = mnt_ctx->root_ses;
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void set_root_ses(struct cifs_mount_ctx *mnt_ctx)
|
||||
static int get_root_smb_session(struct cifs_mount_ctx *mnt_ctx)
|
||||
{
|
||||
if (mnt_ctx->ses) {
|
||||
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
|
||||
struct dfs_root_ses *root_ses;
|
||||
struct cifs_ses *ses = mnt_ctx->ses;
|
||||
|
||||
if (ses) {
|
||||
root_ses = kmalloc(sizeof(*root_ses), GFP_KERNEL);
|
||||
if (!root_ses)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&root_ses->list);
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
mnt_ctx->ses->ses_count++;
|
||||
ses->ses_count++;
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
dfs_cache_add_refsrv_session(&mnt_ctx->mount_id, mnt_ctx->ses);
|
||||
root_ses->ses = ses;
|
||||
list_add_tail(&root_ses->list, &mnt_ctx->dfs_ses_list);
|
||||
}
|
||||
mnt_ctx->root_ses = mnt_ctx->ses;
|
||||
ctx->dfs_root_ses = ses;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, const char *full_path,
|
||||
@ -121,7 +127,8 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co
|
||||
{
|
||||
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
|
||||
struct dfs_info3_param ref = {};
|
||||
int rc;
|
||||
bool is_refsrv = false;
|
||||
int rc, rc2;
|
||||
|
||||
rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref);
|
||||
if (rc)
|
||||
@ -136,8 +143,7 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (ref.flags & DFSREF_REFERRAL_SERVER)
|
||||
set_root_ses(mnt_ctx);
|
||||
is_refsrv = !!(ref.flags & DFSREF_REFERRAL_SERVER);
|
||||
|
||||
rc = -EREMOTE;
|
||||
if (ref.flags & DFSREF_STORAGE_SERVER) {
|
||||
@ -146,13 +152,17 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co
|
||||
goto out;
|
||||
|
||||
/* some servers may not advertise referral capability under ref.flags */
|
||||
if (!(ref.flags & DFSREF_REFERRAL_SERVER) &&
|
||||
is_tcon_dfs(mnt_ctx->tcon))
|
||||
set_root_ses(mnt_ctx);
|
||||
is_refsrv |= is_tcon_dfs(mnt_ctx->tcon);
|
||||
|
||||
rc = cifs_is_path_remote(mnt_ctx);
|
||||
}
|
||||
|
||||
if (rc == -EREMOTE && is_refsrv) {
|
||||
rc2 = get_root_smb_session(mnt_ctx);
|
||||
if (rc2)
|
||||
rc = rc2;
|
||||
}
|
||||
|
||||
out:
|
||||
free_dfs_info_param(&ref);
|
||||
return rc;
|
||||
@ -165,6 +175,7 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
|
||||
char *ref_path = NULL, *full_path = NULL;
|
||||
struct dfs_cache_tgt_iterator *tit;
|
||||
struct TCP_Server_Info *server;
|
||||
struct cifs_tcon *tcon;
|
||||
char *origin_fullpath = NULL;
|
||||
int num_links = 0;
|
||||
int rc;
|
||||
@ -234,12 +245,22 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
|
||||
|
||||
if (!rc) {
|
||||
server = mnt_ctx->server;
|
||||
tcon = mnt_ctx->tcon;
|
||||
|
||||
mutex_lock(&server->refpath_lock);
|
||||
server->origin_fullpath = origin_fullpath;
|
||||
server->current_fullpath = server->leaf_fullpath;
|
||||
if (!server->origin_fullpath) {
|
||||
server->origin_fullpath = origin_fullpath;
|
||||
server->current_fullpath = server->leaf_fullpath;
|
||||
origin_fullpath = NULL;
|
||||
}
|
||||
mutex_unlock(&server->refpath_lock);
|
||||
origin_fullpath = NULL;
|
||||
|
||||
if (list_empty(&tcon->dfs_ses_list)) {
|
||||
list_replace_init(&mnt_ctx->dfs_ses_list,
|
||||
&tcon->dfs_ses_list);
|
||||
} else {
|
||||
dfs_put_root_smb_sessions(&mnt_ctx->dfs_ses_list);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
@ -260,7 +281,7 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
|
||||
rc = get_session(mnt_ctx, NULL);
|
||||
if (rc)
|
||||
return rc;
|
||||
mnt_ctx->root_ses = mnt_ctx->ses;
|
||||
ctx->dfs_root_ses = mnt_ctx->ses;
|
||||
/*
|
||||
* If called with 'nodfs' mount option, then skip DFS resolving. Otherwise unconditionally
|
||||
* try to get an DFS referral (even cached) to determine whether it is an DFS mount.
|
||||
@ -280,7 +301,9 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
|
||||
}
|
||||
|
||||
*isdfs = true;
|
||||
set_root_ses(mnt_ctx);
|
||||
rc = get_root_smb_session(mnt_ctx);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return __dfs_mount_share(mnt_ctx);
|
||||
}
|
||||
|
@ -10,6 +10,11 @@
|
||||
#include "fs_context.h"
|
||||
#include "cifs_unicode.h"
|
||||
|
||||
struct dfs_root_ses {
|
||||
struct list_head list;
|
||||
struct cifs_ses *ses;
|
||||
};
|
||||
|
||||
int dfs_parse_target_referral(const char *full_path, const struct dfs_info3_param *ref,
|
||||
struct smb3_fs_context *ctx);
|
||||
int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs);
|
||||
@ -22,9 +27,10 @@ static inline char *dfs_get_path(struct cifs_sb_info *cifs_sb, const char *path)
|
||||
static inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *path,
|
||||
struct dfs_info3_param *ref, struct dfs_cache_tgt_list *tl)
|
||||
{
|
||||
struct smb3_fs_context *ctx = mnt_ctx->fs_ctx;
|
||||
struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb;
|
||||
|
||||
return dfs_cache_find(mnt_ctx->xid, mnt_ctx->root_ses, cifs_sb->local_nls,
|
||||
return dfs_cache_find(mnt_ctx->xid, ctx->dfs_root_ses, cifs_sb->local_nls,
|
||||
cifs_remap(cifs_sb), path, ref, tl);
|
||||
}
|
||||
|
||||
@ -43,4 +49,15 @@ static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page)
|
||||
true);
|
||||
}
|
||||
|
||||
static inline void dfs_put_root_smb_sessions(struct list_head *head)
|
||||
{
|
||||
struct dfs_root_ses *root, *tmp;
|
||||
|
||||
list_for_each_entry_safe(root, tmp, head, list) {
|
||||
list_del_init(&root->list);
|
||||
cifs_put_smb_ses(root->ses);
|
||||
kfree(root);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _CIFS_DFS_H */
|
||||
|
@ -49,17 +49,6 @@ struct cache_entry {
|
||||
struct cache_dfs_tgt *tgthint;
|
||||
};
|
||||
|
||||
/* List of referral server sessions per dfs mount */
|
||||
struct mount_group {
|
||||
struct list_head list;
|
||||
uuid_t id;
|
||||
struct cifs_ses *sessions[CACHE_MAX_ENTRIES];
|
||||
int num_sessions;
|
||||
spinlock_t lock;
|
||||
struct list_head refresh_list;
|
||||
struct kref refcount;
|
||||
};
|
||||
|
||||
static struct kmem_cache *cache_slab __read_mostly;
|
||||
static struct workqueue_struct *dfscache_wq __read_mostly;
|
||||
|
||||
@ -76,85 +65,10 @@ static atomic_t cache_count;
|
||||
static struct hlist_head cache_htable[CACHE_HTABLE_SIZE];
|
||||
static DECLARE_RWSEM(htable_rw_lock);
|
||||
|
||||
static LIST_HEAD(mount_group_list);
|
||||
static DEFINE_MUTEX(mount_group_list_lock);
|
||||
|
||||
static void refresh_cache_worker(struct work_struct *work);
|
||||
|
||||
static DECLARE_DELAYED_WORK(refresh_task, refresh_cache_worker);
|
||||
|
||||
static void __mount_group_release(struct mount_group *mg)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mg->num_sessions; i++)
|
||||
cifs_put_smb_ses(mg->sessions[i]);
|
||||
kfree(mg);
|
||||
}
|
||||
|
||||
static void mount_group_release(struct kref *kref)
|
||||
{
|
||||
struct mount_group *mg = container_of(kref, struct mount_group, refcount);
|
||||
|
||||
mutex_lock(&mount_group_list_lock);
|
||||
list_del(&mg->list);
|
||||
mutex_unlock(&mount_group_list_lock);
|
||||
__mount_group_release(mg);
|
||||
}
|
||||
|
||||
static struct mount_group *find_mount_group_locked(const uuid_t *id)
|
||||
{
|
||||
struct mount_group *mg;
|
||||
|
||||
list_for_each_entry(mg, &mount_group_list, list) {
|
||||
if (uuid_equal(&mg->id, id))
|
||||
return mg;
|
||||
}
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
static struct mount_group *__get_mount_group_locked(const uuid_t *id)
|
||||
{
|
||||
struct mount_group *mg;
|
||||
|
||||
mg = find_mount_group_locked(id);
|
||||
if (!IS_ERR(mg))
|
||||
return mg;
|
||||
|
||||
mg = kmalloc(sizeof(*mg), GFP_KERNEL);
|
||||
if (!mg)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
kref_init(&mg->refcount);
|
||||
uuid_copy(&mg->id, id);
|
||||
mg->num_sessions = 0;
|
||||
spin_lock_init(&mg->lock);
|
||||
list_add(&mg->list, &mount_group_list);
|
||||
return mg;
|
||||
}
|
||||
|
||||
static struct mount_group *get_mount_group(const uuid_t *id)
|
||||
{
|
||||
struct mount_group *mg;
|
||||
|
||||
mutex_lock(&mount_group_list_lock);
|
||||
mg = __get_mount_group_locked(id);
|
||||
if (!IS_ERR(mg))
|
||||
kref_get(&mg->refcount);
|
||||
mutex_unlock(&mount_group_list_lock);
|
||||
|
||||
return mg;
|
||||
}
|
||||
|
||||
static void free_mount_group_list(void)
|
||||
{
|
||||
struct mount_group *mg, *tmp_mg;
|
||||
|
||||
list_for_each_entry_safe(mg, tmp_mg, &mount_group_list, list) {
|
||||
list_del_init(&mg->list);
|
||||
__mount_group_release(mg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_cache_canonical_path - get a canonical DFS path
|
||||
*
|
||||
@ -704,7 +618,6 @@ void dfs_cache_destroy(void)
|
||||
{
|
||||
cancel_delayed_work_sync(&refresh_task);
|
||||
unload_nls(cache_cp);
|
||||
free_mount_group_list();
|
||||
flush_cache_ents();
|
||||
kmem_cache_destroy(cache_slab);
|
||||
destroy_workqueue(dfscache_wq);
|
||||
@ -1111,54 +1024,6 @@ out_unlock:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_cache_add_refsrv_session - add SMB session of referral server
|
||||
*
|
||||
* @mount_id: mount group uuid to lookup.
|
||||
* @ses: reference counted SMB session of referral server.
|
||||
*/
|
||||
void dfs_cache_add_refsrv_session(const uuid_t *mount_id, struct cifs_ses *ses)
|
||||
{
|
||||
struct mount_group *mg;
|
||||
|
||||
if (WARN_ON_ONCE(!mount_id || uuid_is_null(mount_id) || !ses))
|
||||
return;
|
||||
|
||||
mg = get_mount_group(mount_id);
|
||||
if (WARN_ON_ONCE(IS_ERR(mg)))
|
||||
return;
|
||||
|
||||
spin_lock(&mg->lock);
|
||||
if (mg->num_sessions < ARRAY_SIZE(mg->sessions))
|
||||
mg->sessions[mg->num_sessions++] = ses;
|
||||
spin_unlock(&mg->lock);
|
||||
kref_put(&mg->refcount, mount_group_release);
|
||||
}
|
||||
|
||||
/**
|
||||
* dfs_cache_put_refsrv_sessions - put all referral server sessions
|
||||
*
|
||||
* Put all SMB sessions from the given mount group id.
|
||||
*
|
||||
* @mount_id: mount group uuid to lookup.
|
||||
*/
|
||||
void dfs_cache_put_refsrv_sessions(const uuid_t *mount_id)
|
||||
{
|
||||
struct mount_group *mg;
|
||||
|
||||
if (!mount_id || uuid_is_null(mount_id))
|
||||
return;
|
||||
|
||||
mutex_lock(&mount_group_list_lock);
|
||||
mg = find_mount_group_locked(mount_id);
|
||||
if (IS_ERR(mg)) {
|
||||
mutex_unlock(&mount_group_list_lock);
|
||||
return;
|
||||
}
|
||||
mutex_unlock(&mount_group_list_lock);
|
||||
kref_put(&mg->refcount, mount_group_release);
|
||||
}
|
||||
|
||||
/* Extract share from DFS target and return a pointer to prefix path or NULL */
|
||||
static const char *parse_target_share(const char *target, char **share)
|
||||
{
|
||||
@ -1384,11 +1249,6 @@ int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb)
|
||||
cifs_dbg(FYI, "%s: not a dfs mount\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uuid_is_null(&cifs_sb->dfs_mount_id)) {
|
||||
cifs_dbg(FYI, "%s: no dfs mount group id\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* After reconnecting to a different server, unique ids won't match anymore, so we disable
|
||||
* serverino. This prevents dentry revalidation to think the dentry are stale (ESTALE).
|
||||
|
@ -40,8 +40,6 @@ int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iter
|
||||
struct dfs_info3_param *ref);
|
||||
int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, char **share,
|
||||
char **prefix);
|
||||
void dfs_cache_put_refsrv_sessions(const uuid_t *mount_id);
|
||||
void dfs_cache_add_refsrv_session(const uuid_t *mount_id, struct cifs_ses *ses);
|
||||
char *dfs_cache_canonical_path(const char *path, const struct nls_table *cp, int remap);
|
||||
int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb);
|
||||
|
||||
|
@ -265,6 +265,7 @@ struct smb3_fs_context {
|
||||
bool rootfs:1; /* if it's a SMB root file system */
|
||||
bool witness:1; /* use witness protocol */
|
||||
char *leaf_fullpath;
|
||||
struct cifs_ses *dfs_root_ses;
|
||||
};
|
||||
|
||||
extern const struct fs_parameter_spec smb3_fs_parameters[];
|
||||
|
@ -22,6 +22,7 @@
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
#include "dns_resolve.h"
|
||||
#include "dfs_cache.h"
|
||||
#include "dfs.h"
|
||||
#endif
|
||||
#include "fs_context.h"
|
||||
#include "cached_dir.h"
|
||||
@ -134,6 +135,9 @@ tconInfoAlloc(void)
|
||||
spin_lock_init(&ret_buf->stat_lock);
|
||||
atomic_set(&ret_buf->num_local_opens, 0);
|
||||
atomic_set(&ret_buf->num_remote_opens, 0);
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
INIT_LIST_HEAD(&ret_buf->dfs_ses_list);
|
||||
#endif
|
||||
|
||||
return ret_buf;
|
||||
}
|
||||
@ -149,6 +153,9 @@ tconInfoFree(struct cifs_tcon *tcon)
|
||||
atomic_dec(&tconInfoAllocCount);
|
||||
kfree(tcon->nativeFileSystem);
|
||||
kfree_sensitive(tcon->password);
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
dfs_put_root_smb_sessions(&tcon->dfs_ses_list);
|
||||
#endif
|
||||
kfree(tcon);
|
||||
}
|
||||
|
||||
@ -1255,6 +1262,7 @@ int cifs_inval_name_dfs_link_error(const unsigned int xid,
|
||||
* removing cached DFS targets that the client would eventually
|
||||
* need during failover.
|
||||
*/
|
||||
ses = CIFS_DFS_ROOT_SES(ses);
|
||||
if (ses->server->ops->get_dfs_refer &&
|
||||
!ses->server->ops->get_dfs_refer(xid, ses, ref_path, &refs,
|
||||
&num_refs, cifs_sb->local_nls,
|
||||
|
@ -234,15 +234,32 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
size[0] = 8; /* sizeof __le64 */
|
||||
data[0] = ptr;
|
||||
|
||||
rc = SMB2_set_info_init(tcon, server,
|
||||
&rqst[num_rqst], COMPOUND_FID,
|
||||
COMPOUND_FID, current->tgid,
|
||||
FILE_END_OF_FILE_INFORMATION,
|
||||
SMB2_O_INFO_FILE, 0, data, size);
|
||||
if (cfile) {
|
||||
rc = SMB2_set_info_init(tcon, server,
|
||||
&rqst[num_rqst],
|
||||
cfile->fid.persistent_fid,
|
||||
cfile->fid.volatile_fid,
|
||||
current->tgid,
|
||||
FILE_END_OF_FILE_INFORMATION,
|
||||
SMB2_O_INFO_FILE, 0,
|
||||
data, size);
|
||||
} else {
|
||||
rc = SMB2_set_info_init(tcon, server,
|
||||
&rqst[num_rqst],
|
||||
COMPOUND_FID,
|
||||
COMPOUND_FID,
|
||||
current->tgid,
|
||||
FILE_END_OF_FILE_INFORMATION,
|
||||
SMB2_O_INFO_FILE, 0,
|
||||
data, size);
|
||||
if (!rc) {
|
||||
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||
smb2_set_related(&rqst[num_rqst]);
|
||||
}
|
||||
}
|
||||
if (rc)
|
||||
goto finished;
|
||||
smb2_set_next_command(tcon, &rqst[num_rqst]);
|
||||
smb2_set_related(&rqst[num_rqst++]);
|
||||
num_rqst++;
|
||||
trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
|
||||
break;
|
||||
case SMB2_OP_SET_INFO:
|
||||
|
@ -425,7 +425,7 @@ generate_smb3signingkey(struct cifs_ses *ses,
|
||||
|
||||
/* safe to access primary channel, since it will never go away */
|
||||
spin_lock(&ses->chan_lock);
|
||||
memcpy(ses->chans[0].signkey, ses->smb3signingkey,
|
||||
memcpy(ses->chans[chan_index].signkey, ses->smb3signingkey,
|
||||
SMB3_SIGN_KEY_SIZE);
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
|
@ -278,7 +278,7 @@ static int
|
||||
__smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
||||
struct smb_rqst *rqst)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc;
|
||||
struct kvec *iov;
|
||||
int n_vec;
|
||||
unsigned int send_length = 0;
|
||||
@ -289,6 +289,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
||||
struct msghdr smb_msg = {};
|
||||
__be32 rfc1002_marker;
|
||||
|
||||
cifs_in_send_inc(server);
|
||||
if (cifs_rdma_enabled(server)) {
|
||||
/* return -EAGAIN when connecting or reconnecting */
|
||||
rc = -EAGAIN;
|
||||
@ -297,14 +298,17 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
||||
goto smbd_done;
|
||||
}
|
||||
|
||||
rc = -EAGAIN;
|
||||
if (ssocket == NULL)
|
||||
return -EAGAIN;
|
||||
goto out;
|
||||
|
||||
rc = -ERESTARTSYS;
|
||||
if (fatal_signal_pending(current)) {
|
||||
cifs_dbg(FYI, "signal pending before send request\n");
|
||||
return -ERESTARTSYS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
/* cork the socket */
|
||||
tcp_sock_set_cork(ssocket->sk, true);
|
||||
|
||||
@ -407,7 +411,8 @@ smbd_done:
|
||||
rc);
|
||||
else if (rc > 0)
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
cifs_in_send_dec(server);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -826,9 +831,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
||||
* I/O response may come back and free the mid entry on another thread.
|
||||
*/
|
||||
cifs_save_when_sent(mid);
|
||||
cifs_in_send_inc(server);
|
||||
rc = smb_send_rqst(server, 1, rqst, flags);
|
||||
cifs_in_send_dec(server);
|
||||
|
||||
if (rc < 0) {
|
||||
revert_current_mid(server, mid->credits);
|
||||
@ -1144,9 +1147,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
|
||||
else
|
||||
midQ[i]->callback = cifs_compound_last_callback;
|
||||
}
|
||||
cifs_in_send_inc(server);
|
||||
rc = smb_send_rqst(server, num_rqst, rqst, flags);
|
||||
cifs_in_send_dec(server);
|
||||
|
||||
for (i = 0; i < num_rqst; i++)
|
||||
cifs_save_when_sent(midQ[i]);
|
||||
@ -1396,9 +1397,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
|
||||
|
||||
midQ->mid_state = MID_REQUEST_SUBMITTED;
|
||||
|
||||
cifs_in_send_inc(server);
|
||||
rc = smb_send(server, in_buf, len);
|
||||
cifs_in_send_dec(server);
|
||||
cifs_save_when_sent(midQ);
|
||||
|
||||
if (rc < 0)
|
||||
@ -1539,9 +1538,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
}
|
||||
|
||||
midQ->mid_state = MID_REQUEST_SUBMITTED;
|
||||
cifs_in_send_inc(server);
|
||||
rc = smb_send(server, in_buf, len);
|
||||
cifs_in_send_dec(server);
|
||||
cifs_save_when_sent(midQ);
|
||||
|
||||
if (rc < 0)
|
||||
|
Loading…
Reference in New Issue
Block a user