Commit 38e04b3e authored by Linus Torvalds's avatar Linus Torvalds

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()
parents 0ddc84d2 6284e46b
...@@ -420,6 +420,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) ...@@ -420,6 +420,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
from_kuid(&init_user_ns, ses->linux_uid), from_kuid(&init_user_ns, ses->linux_uid),
from_kuid(&init_user_ns, ses->cred_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); spin_lock(&ses->chan_lock);
if (CIFS_CHAN_NEEDS_RECONNECT(ses, 0)) if (CIFS_CHAN_NEEDS_RECONNECT(ses, 0))
seq_puts(m, "\tPrimary channel: DISCONNECTED "); seq_puts(m, "\tPrimary channel: DISCONNECTED ");
......
...@@ -179,6 +179,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path) ...@@ -179,6 +179,7 @@ static struct vfsmount *cifs_dfs_do_automount(struct path *path)
tmp.source = full_path; tmp.source = full_path;
tmp.leaf_fullpath = NULL; tmp.leaf_fullpath = NULL;
tmp.UNC = tmp.prepath = NULL; tmp.UNC = tmp.prepath = NULL;
tmp.dfs_root_ses = NULL;
rc = smb3_fs_context_dup(ctx, &tmp); rc = smb3_fs_context_dup(ctx, &tmp);
if (rc) { if (rc) {
......
...@@ -61,8 +61,6 @@ struct cifs_sb_info { ...@@ -61,8 +61,6 @@ struct cifs_sb_info {
/* only used when CIFS_MOUNT_USE_PREFIX_PATH is set */ /* only used when CIFS_MOUNT_USE_PREFIX_PATH is set */
char *prepath; 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 * Indicate whether serverino option was turned off later
* (cifs_autodisable_serverino) in order to match new mounts. * (cifs_autodisable_serverino) in order to match new mounts.
......
...@@ -1233,6 +1233,7 @@ struct cifs_tcon { ...@@ -1233,6 +1233,7 @@ struct cifs_tcon {
/* BB add field for back pointer to sb struct(s)? */ /* BB add field for back pointer to sb struct(s)? */
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
struct list_head ulist; /* cache update list */ struct list_head ulist; /* cache update list */
struct list_head dfs_ses_list;
#endif #endif
struct delayed_work query_interfaces; /* query interfaces workqueue job */ struct delayed_work query_interfaces; /* query interfaces workqueue job */
}; };
...@@ -1749,9 +1750,8 @@ struct cifs_mount_ctx { ...@@ -1749,9 +1750,8 @@ struct cifs_mount_ctx {
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
struct cifs_ses *ses; struct cifs_ses *ses;
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct cifs_ses *root_ses;
uuid_t mount_id;
char *origin_fullpath, *leaf_fullpath; char *origin_fullpath, *leaf_fullpath;
struct list_head dfs_ses_list;
}; };
static inline void free_dfs_info_param(struct dfs_info3_param *param) 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) ...@@ -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. * need to lock before changing something in the session.
*/ */
spin_lock(&cifs_tcp_ses_lock); spin_lock(&cifs_tcp_ses_lock);
ses->dfs_root_ses = ctx->dfs_root_ses;
list_add(&ses->smb_ses_list, &server->smb_ses_list); list_add(&ses->smb_ses_list, &server->smb_ses_list);
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
...@@ -3407,7 +3408,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) ...@@ -3407,7 +3408,8 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
bool isdfs; bool isdfs;
int rc; int rc;
uuid_gen(&mnt_ctx.mount_id); INIT_LIST_HEAD(&mnt_ctx.dfs_ses_list);
rc = dfs_mount_share(&mnt_ctx, &isdfs); rc = dfs_mount_share(&mnt_ctx, &isdfs);
if (rc) if (rc)
goto error; goto error;
...@@ -3427,7 +3429,6 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) ...@@ -3427,7 +3429,6 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
kfree(cifs_sb->prepath); kfree(cifs_sb->prepath);
cifs_sb->prepath = ctx->prepath; cifs_sb->prepath = ctx->prepath;
ctx->prepath = NULL; ctx->prepath = NULL;
uuid_copy(&cifs_sb->dfs_mount_id, &mnt_ctx.mount_id);
out: out:
cifs_try_adding_channels(cifs_sb, mnt_ctx.ses); cifs_try_adding_channels(cifs_sb, mnt_ctx.ses);
...@@ -3439,7 +3440,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx) ...@@ -3439,7 +3440,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
return rc; return rc;
error: 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.origin_fullpath);
kfree(mnt_ctx.leaf_fullpath); kfree(mnt_ctx.leaf_fullpath);
cifs_mount_put_conns(&mnt_ctx); cifs_mount_put_conns(&mnt_ctx);
...@@ -3637,9 +3638,6 @@ cifs_umount(struct cifs_sb_info *cifs_sb) ...@@ -3637,9 +3638,6 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
spin_unlock(&cifs_sb->tlink_tree_lock); spin_unlock(&cifs_sb->tlink_tree_lock);
kfree(cifs_sb->prepath); 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); 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) ...@@ -95,25 +95,31 @@ static int get_session(struct cifs_mount_ctx *mnt_ctx, const char *full_path)
ctx->leaf_fullpath = (char *)full_path; ctx->leaf_fullpath = (char *)full_path;
rc = cifs_mount_get_session(mnt_ctx); rc = cifs_mount_get_session(mnt_ctx);
ctx->leaf_fullpath = NULL; 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; 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); spin_lock(&cifs_tcp_ses_lock);
mnt_ctx->ses->ses_count++; ses->ses_count++;
spin_unlock(&cifs_tcp_ses_lock); 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, 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 ...@@ -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 smb3_fs_context *ctx = mnt_ctx->fs_ctx;
struct dfs_info3_param ref = {}; 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); rc = dfs_cache_get_tgt_referral(ref_path + 1, tit, &ref);
if (rc) if (rc)
...@@ -136,8 +143,7 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co ...@@ -136,8 +143,7 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co
if (rc) if (rc)
goto out; goto out;
if (ref.flags & DFSREF_REFERRAL_SERVER) is_refsrv = !!(ref.flags & DFSREF_REFERRAL_SERVER);
set_root_ses(mnt_ctx);
rc = -EREMOTE; rc = -EREMOTE;
if (ref.flags & DFSREF_STORAGE_SERVER) { 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 ...@@ -146,13 +152,17 @@ static int get_dfs_conn(struct cifs_mount_ctx *mnt_ctx, const char *ref_path, co
goto out; goto out;
/* some servers may not advertise referral capability under ref.flags */ /* some servers may not advertise referral capability under ref.flags */
if (!(ref.flags & DFSREF_REFERRAL_SERVER) && is_refsrv |= is_tcon_dfs(mnt_ctx->tcon);
is_tcon_dfs(mnt_ctx->tcon))
set_root_ses(mnt_ctx);
rc = cifs_is_path_remote(mnt_ctx); rc = cifs_is_path_remote(mnt_ctx);
} }
if (rc == -EREMOTE && is_refsrv) {
rc2 = get_root_smb_session(mnt_ctx);
if (rc2)
rc = rc2;
}
out: out:
free_dfs_info_param(&ref); free_dfs_info_param(&ref);
return rc; return rc;
...@@ -165,6 +175,7 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) ...@@ -165,6 +175,7 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
char *ref_path = NULL, *full_path = NULL; char *ref_path = NULL, *full_path = NULL;
struct dfs_cache_tgt_iterator *tit; struct dfs_cache_tgt_iterator *tit;
struct TCP_Server_Info *server; struct TCP_Server_Info *server;
struct cifs_tcon *tcon;
char *origin_fullpath = NULL; char *origin_fullpath = NULL;
int num_links = 0; int num_links = 0;
int rc; int rc;
...@@ -234,13 +245,23 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx) ...@@ -234,13 +245,23 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
if (!rc) { if (!rc) {
server = mnt_ctx->server; server = mnt_ctx->server;
tcon = mnt_ctx->tcon;
mutex_lock(&server->refpath_lock); mutex_lock(&server->refpath_lock);
if (!server->origin_fullpath) {
server->origin_fullpath = origin_fullpath; server->origin_fullpath = origin_fullpath;
server->current_fullpath = server->leaf_fullpath; server->current_fullpath = server->leaf_fullpath;
mutex_unlock(&server->refpath_lock);
origin_fullpath = NULL; origin_fullpath = NULL;
} }
mutex_unlock(&server->refpath_lock);
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: out:
kfree(origin_fullpath); kfree(origin_fullpath);
...@@ -260,7 +281,7 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs) ...@@ -260,7 +281,7 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
rc = get_session(mnt_ctx, NULL); rc = get_session(mnt_ctx, NULL);
if (rc) if (rc)
return 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 * 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. * 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) ...@@ -280,7 +301,9 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
} }
*isdfs = true; *isdfs = true;
set_root_ses(mnt_ctx); rc = get_root_smb_session(mnt_ctx);
if (rc)
return rc;
return __dfs_mount_share(mnt_ctx); return __dfs_mount_share(mnt_ctx);
} }
......
...@@ -10,6 +10,11 @@ ...@@ -10,6 +10,11 @@
#include "fs_context.h" #include "fs_context.h"
#include "cifs_unicode.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, int dfs_parse_target_referral(const char *full_path, const struct dfs_info3_param *ref,
struct smb3_fs_context *ctx); struct smb3_fs_context *ctx);
int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs); 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) ...@@ -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, 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 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; 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); cifs_remap(cifs_sb), path, ref, tl);
} }
...@@ -43,4 +49,15 @@ static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page) ...@@ -43,4 +49,15 @@ static inline char *dfs_get_automount_devname(struct dentry *dentry, void *page)
true); 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 */ #endif /* _CIFS_DFS_H */
...@@ -49,17 +49,6 @@ struct cache_entry { ...@@ -49,17 +49,6 @@ struct cache_entry {
struct cache_dfs_tgt *tgthint; 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 kmem_cache *cache_slab __read_mostly;
static struct workqueue_struct *dfscache_wq __read_mostly; static struct workqueue_struct *dfscache_wq __read_mostly;
...@@ -76,85 +65,10 @@ static atomic_t cache_count; ...@@ -76,85 +65,10 @@ static atomic_t cache_count;
static struct hlist_head cache_htable[CACHE_HTABLE_SIZE]; static struct hlist_head cache_htable[CACHE_HTABLE_SIZE];
static DECLARE_RWSEM(htable_rw_lock); 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 void refresh_cache_worker(struct work_struct *work);
static DECLARE_DELAYED_WORK(refresh_task, refresh_cache_worker); 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 * dfs_cache_canonical_path - get a canonical DFS path
* *
...@@ -704,7 +618,6 @@ void dfs_cache_destroy(void) ...@@ -704,7 +618,6 @@ void dfs_cache_destroy(void)
{ {
cancel_delayed_work_sync(&refresh_task); cancel_delayed_work_sync(&refresh_task);
unload_nls(cache_cp); unload_nls(cache_cp);
free_mount_group_list();
flush_cache_ents(); flush_cache_ents();
kmem_cache_destroy(cache_slab); kmem_cache_destroy(cache_slab);
destroy_workqueue(dfscache_wq); destroy_workqueue(dfscache_wq);
...@@ -1111,54 +1024,6 @@ int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iter ...@@ -1111,54 +1024,6 @@ int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iter
return rc; 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 */ /* 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) 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) ...@@ -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__); cifs_dbg(FYI, "%s: not a dfs mount\n", __func__);
return 0; 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 * 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). * 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 ...@@ -40,8 +40,6 @@ int dfs_cache_get_tgt_referral(const char *path, const struct dfs_cache_tgt_iter
struct dfs_info3_param *ref); struct dfs_info3_param *ref);
int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, char **share, int dfs_cache_get_tgt_share(char *path, const struct dfs_cache_tgt_iterator *it, char **share,
char **prefix); 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); 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); int dfs_cache_remount_fs(struct cifs_sb_info *cifs_sb);
......
...@@ -265,6 +265,7 @@ struct smb3_fs_context { ...@@ -265,6 +265,7 @@ struct smb3_fs_context {
bool rootfs:1; /* if it's a SMB root file system */ bool rootfs:1; /* if it's a SMB root file system */
bool witness:1; /* use witness protocol */ bool witness:1; /* use witness protocol */
char *leaf_fullpath; char *leaf_fullpath;
struct cifs_ses *dfs_root_ses;
}; };
extern const struct fs_parameter_spec smb3_fs_parameters[]; extern const struct fs_parameter_spec smb3_fs_parameters[];
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#ifdef CONFIG_CIFS_DFS_UPCALL #ifdef CONFIG_CIFS_DFS_UPCALL
#include "dns_resolve.h" #include "dns_resolve.h"
#include "dfs_cache.h" #include "dfs_cache.h"
#include "dfs.h"
#endif #endif
#include "fs_context.h" #include "fs_context.h"
#include "cached_dir.h" #include "cached_dir.h"
...@@ -134,6 +135,9 @@ tconInfoAlloc(void) ...@@ -134,6 +135,9 @@ tconInfoAlloc(void)
spin_lock_init(&ret_buf->stat_lock); spin_lock_init(&ret_buf->stat_lock);
atomic_set(&ret_buf->num_local_opens, 0); atomic_set(&ret_buf->num_local_opens, 0);
atomic_set(&ret_buf->num_remote_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; return ret_buf;
} }
...@@ -149,6 +153,9 @@ tconInfoFree(struct cifs_tcon *tcon) ...@@ -149,6 +153,9 @@ tconInfoFree(struct cifs_tcon *tcon)
atomic_dec(&tconInfoAllocCount); atomic_dec(&tconInfoAllocCount);
kfree(tcon->nativeFileSystem); kfree(tcon->nativeFileSystem);
kfree_sensitive(tcon->password); kfree_sensitive(tcon->password);
#ifdef CONFIG_CIFS_DFS_UPCALL
dfs_put_root_smb_sessions(&tcon->dfs_ses_list);
#endif
kfree(tcon); kfree(tcon);
} }
...@@ -1255,6 +1262,7 @@ int cifs_inval_name_dfs_link_error(const unsigned int xid, ...@@ -1255,6 +1262,7 @@ int cifs_inval_name_dfs_link_error(const unsigned int xid,
* removing cached DFS targets that the client would eventually * removing cached DFS targets that the client would eventually
* need during failover. * need during failover.
*/ */
ses = CIFS_DFS_ROOT_SES(ses);
if (ses->server->ops->get_dfs_refer && if (ses->server->ops->get_dfs_refer &&
!ses->server->ops->get_dfs_refer(xid, ses, ref_path, &refs, !ses->server->ops->get_dfs_refer(xid, ses, ref_path, &refs,
&num_refs, cifs_sb->local_nls, &num_refs, cifs_sb->local_nls,
......
...@@ -234,15 +234,32 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -234,15 +234,32 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
size[0] = 8; /* sizeof __le64 */ size[0] = 8; /* sizeof __le64 */
data[0] = ptr; data[0] = ptr;
if (cfile) {
rc = SMB2_set_info_init(tcon, server, rc = SMB2_set_info_init(tcon, server,
&rqst[num_rqst], COMPOUND_FID, &rqst[num_rqst],
COMPOUND_FID, current->tgid, cfile->fid.persistent_fid,
cfile->fid.volatile_fid,
current->tgid,
FILE_END_OF_FILE_INFORMATION, FILE_END_OF_FILE_INFORMATION,
SMB2_O_INFO_FILE, 0, data, size); 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) if (rc)
goto finished; goto finished;
smb2_set_next_command(tcon, &rqst[num_rqst]); num_rqst++;
smb2_set_related(&rqst[num_rqst++]);
trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path); trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
break; break;
case SMB2_OP_SET_INFO: case SMB2_OP_SET_INFO:
......
...@@ -425,7 +425,7 @@ generate_smb3signingkey(struct cifs_ses *ses, ...@@ -425,7 +425,7 @@ generate_smb3signingkey(struct cifs_ses *ses,
/* safe to access primary channel, since it will never go away */ /* safe to access primary channel, since it will never go away */
spin_lock(&ses->chan_lock); spin_lock(&ses->chan_lock);
memcpy(ses->chans[0].signkey, ses->smb3signingkey, memcpy(ses->chans[chan_index].signkey, ses->smb3signingkey,
SMB3_SIGN_KEY_SIZE); SMB3_SIGN_KEY_SIZE);
spin_unlock(&ses->chan_lock); spin_unlock(&ses->chan_lock);
......
...@@ -278,7 +278,7 @@ static int ...@@ -278,7 +278,7 @@ static int
__smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
struct smb_rqst *rqst) struct smb_rqst *rqst)
{ {
int rc = 0; int rc;
struct kvec *iov; struct kvec *iov;
int n_vec; int n_vec;
unsigned int send_length = 0; unsigned int send_length = 0;
...@@ -289,6 +289,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, ...@@ -289,6 +289,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
struct msghdr smb_msg = {}; struct msghdr smb_msg = {};
__be32 rfc1002_marker; __be32 rfc1002_marker;
cifs_in_send_inc(server);
if (cifs_rdma_enabled(server)) { if (cifs_rdma_enabled(server)) {
/* return -EAGAIN when connecting or reconnecting */ /* return -EAGAIN when connecting or reconnecting */
rc = -EAGAIN; rc = -EAGAIN;
...@@ -297,14 +298,17 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, ...@@ -297,14 +298,17 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
goto smbd_done; goto smbd_done;
} }
rc = -EAGAIN;
if (ssocket == NULL) if (ssocket == NULL)
return -EAGAIN; goto out;
rc = -ERESTARTSYS;
if (fatal_signal_pending(current)) { if (fatal_signal_pending(current)) {
cifs_dbg(FYI, "signal pending before send request\n"); cifs_dbg(FYI, "signal pending before send request\n");
return -ERESTARTSYS; goto out;
} }
rc = 0;
/* cork the socket */ /* cork the socket */
tcp_sock_set_cork(ssocket->sk, true); tcp_sock_set_cork(ssocket->sk, true);
...@@ -407,7 +411,8 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, ...@@ -407,7 +411,8 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
rc); rc);
else if (rc > 0) else if (rc > 0)
rc = 0; rc = 0;
out:
cifs_in_send_dec(server);
return rc; return rc;
} }
...@@ -826,9 +831,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, ...@@ -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. * I/O response may come back and free the mid entry on another thread.
*/ */
cifs_save_when_sent(mid); cifs_save_when_sent(mid);
cifs_in_send_inc(server);
rc = smb_send_rqst(server, 1, rqst, flags); rc = smb_send_rqst(server, 1, rqst, flags);
cifs_in_send_dec(server);
if (rc < 0) { if (rc < 0) {
revert_current_mid(server, mid->credits); revert_current_mid(server, mid->credits);
...@@ -1144,9 +1147,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, ...@@ -1144,9 +1147,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
else else
midQ[i]->callback = cifs_compound_last_callback; midQ[i]->callback = cifs_compound_last_callback;
} }
cifs_in_send_inc(server);
rc = smb_send_rqst(server, num_rqst, rqst, flags); rc = smb_send_rqst(server, num_rqst, rqst, flags);
cifs_in_send_dec(server);
for (i = 0; i < num_rqst; i++) for (i = 0; i < num_rqst; i++)
cifs_save_when_sent(midQ[i]); cifs_save_when_sent(midQ[i]);
...@@ -1396,9 +1397,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, ...@@ -1396,9 +1397,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
midQ->mid_state = MID_REQUEST_SUBMITTED; midQ->mid_state = MID_REQUEST_SUBMITTED;
cifs_in_send_inc(server);
rc = smb_send(server, in_buf, len); rc = smb_send(server, in_buf, len);
cifs_in_send_dec(server);
cifs_save_when_sent(midQ); cifs_save_when_sent(midQ);
if (rc < 0) if (rc < 0)
...@@ -1539,9 +1538,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1539,9 +1538,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
} }
midQ->mid_state = MID_REQUEST_SUBMITTED; midQ->mid_state = MID_REQUEST_SUBMITTED;
cifs_in_send_inc(server);
rc = smb_send(server, in_buf, len); rc = smb_send(server, in_buf, len);
cifs_in_send_dec(server);
cifs_save_when_sent(midQ); cifs_save_when_sent(midQ);
if (rc < 0) if (rc < 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment