mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 17:25:38 +00:00
22 SMB3 client fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmdKXd4ACgkQiiy9cAdy T1FjCwv/f3lb79FaVhv18LAvayqoj+iWaZg6yYepZxp2hyMTm59i5I1t7Ar92VES 2+A3XmdeK5U6y9JjMFYHY4B720JumBDTJ/FPgUPZtZqCHSnYZCm5MUQtH85VSisf /4Ua5kv5tzCuu9UvoCp3UFcsbCCrXH8JYTBGR2EKfIHqN7ae1F80pLgBxEnBuuw9 rRx0RKxKb9CkYB8GDOHi60hF03DRlXdMa7I/aJ6dtyhZkzoDgc0PqndFQuwLMY07 f09rnXnDvHqqC+SFHprqE6V8uWl77IX6lzZ4PCz52dsm6Y/BKD22fBQA3w4zz/0s nMvxbEaxcealSq08pTn7zWVi0tw7Ku35c0plXCtjzS4UmcouMdwI6SP986IqEH+C 0la/mDnPk36EQYdd1yYVYAcbW9VrmiYs23PvKfH4Hj6JvQeZ872RnMYZPPl+jJh6 Gazdn3yWRiKRuTcO42eC+JKaoJKG/JBqkd74WBe85Q0yVNf2m0CJEICfAcWDlK/Z fIl3WxjN =dfo/ -----END PGP SIGNATURE----- Merge tag '6.13-rc-part2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull smb client updates from Steve French: - directory lease fixes - password rotation fixes - reconnect fix - fix for SMB3.02 mounts - DFS (global namespace) fixes - fixes for special file handling (most relating to better handling various types of symlinks) - two minor cleanups * tag '6.13-rc-part2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: (22 commits) cifs: update internal version number cifs: unlock on error in smb3_reconfigure() cifs: during remount, make sure passwords are in sync cifs: support mounting with alternate password to allow password rotation smb: Initialize cfid->tcon before performing network ops smb: During unmount, ensure all cached dir instances drop their dentry smb: client: fix noisy message when mounting shares smb: client: don't try following DFS links in cifs_tree_connect() smb: client: allow reconnect when sending ioctl smb: client: get rid of @nlsc param in cifs_tree_connect() smb: client: allow more DFS referrals to be cached cifs: Fix parsing reparse point with native symlink in SMB1 non-UNICODE session cifs: Validate content of WSL reparse point buffers cifs: Improve guard for excluding $LXDEV xattr cifs: Add support for parsing WSL-style symlinks cifs: Validate content of native symlink cifs: Fix parsing native symlinks relative to the export smb: client: fix NULL ptr deref in crypto_aead_setkey() Update misleading comment in cifs_chan_update_iface smb: client: change return value in open_cached_dir_by_dentry() if !cfids ...
This commit is contained in:
commit
0235da0fae
@ -17,6 +17,11 @@ static void free_cached_dir(struct cached_fid *cfid);
|
||||
static void smb2_close_cached_fid(struct kref *ref);
|
||||
static void cfids_laundromat_worker(struct work_struct *work);
|
||||
|
||||
struct cached_dir_dentry {
|
||||
struct list_head entry;
|
||||
struct dentry *dentry;
|
||||
};
|
||||
|
||||
static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
|
||||
const char *path,
|
||||
bool lookup_only,
|
||||
@ -157,15 +162,17 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *npath;
|
||||
int retries = 0, cur_sleep = 1;
|
||||
|
||||
if (tcon == NULL || tcon->cfids == NULL || tcon->nohandlecache ||
|
||||
is_smb1_server(tcon->ses->server) || (dir_cache_timeout == 0))
|
||||
if (cifs_sb->root == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
if (tcon == NULL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ses = tcon->ses;
|
||||
cfids = tcon->cfids;
|
||||
|
||||
if (cifs_sb->root == NULL)
|
||||
return -ENOENT;
|
||||
if (cfids == NULL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
replay_again:
|
||||
/* reinitialize for possible replay */
|
||||
@ -222,6 +229,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
|
||||
}
|
||||
}
|
||||
cfid->dentry = dentry;
|
||||
cfid->tcon = tcon;
|
||||
|
||||
/*
|
||||
* We do not hold the lock for the open because in case
|
||||
@ -293,7 +301,6 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
|
||||
}
|
||||
goto oshr_free;
|
||||
}
|
||||
cfid->tcon = tcon;
|
||||
cfid->is_open = true;
|
||||
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
@ -389,7 +396,7 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
|
||||
struct cached_fids *cfids = tcon->cfids;
|
||||
|
||||
if (cfids == NULL)
|
||||
return -ENOENT;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
list_for_each_entry(cfid, &cfids->entries, entry) {
|
||||
@ -470,7 +477,10 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
|
||||
struct cifs_tcon *tcon;
|
||||
struct tcon_link *tlink;
|
||||
struct cached_fids *cfids;
|
||||
struct cached_dir_dentry *tmp_list, *q;
|
||||
LIST_HEAD(entry);
|
||||
|
||||
spin_lock(&cifs_sb->tlink_tree_lock);
|
||||
for (node = rb_first(root); node; node = rb_next(node)) {
|
||||
tlink = rb_entry(node, struct tcon_link, tl_rbnode);
|
||||
tcon = tlink_tcon(tlink);
|
||||
@ -479,11 +489,30 @@ void close_all_cached_dirs(struct cifs_sb_info *cifs_sb)
|
||||
cfids = tcon->cfids;
|
||||
if (cfids == NULL)
|
||||
continue;
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
list_for_each_entry(cfid, &cfids->entries, entry) {
|
||||
dput(cfid->dentry);
|
||||
tmp_list = kmalloc(sizeof(*tmp_list), GFP_ATOMIC);
|
||||
if (tmp_list == NULL)
|
||||
break;
|
||||
spin_lock(&cfid->fid_lock);
|
||||
tmp_list->dentry = cfid->dentry;
|
||||
cfid->dentry = NULL;
|
||||
spin_unlock(&cfid->fid_lock);
|
||||
|
||||
list_add_tail(&tmp_list->entry, &entry);
|
||||
}
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
}
|
||||
spin_unlock(&cifs_sb->tlink_tree_lock);
|
||||
|
||||
list_for_each_entry_safe(tmp_list, q, &entry, entry) {
|
||||
list_del(&tmp_list->entry);
|
||||
dput(tmp_list->dentry);
|
||||
kfree(tmp_list);
|
||||
}
|
||||
|
||||
/* Flush any pending work that will drop dentries */
|
||||
flush_workqueue(cfid_put_wq);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -494,14 +523,18 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
|
||||
{
|
||||
struct cached_fids *cfids = tcon->cfids;
|
||||
struct cached_fid *cfid, *q;
|
||||
LIST_HEAD(entry);
|
||||
|
||||
if (cfids == NULL)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Mark all the cfids as closed, and move them to the cfids->dying list.
|
||||
* They'll be cleaned up later by cfids_invalidation_worker. Take
|
||||
* a reference to each cfid during this process.
|
||||
*/
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
|
||||
list_move(&cfid->entry, &entry);
|
||||
list_move(&cfid->entry, &cfids->dying);
|
||||
cfids->num_entries--;
|
||||
cfid->is_open = false;
|
||||
cfid->on_list = false;
|
||||
@ -514,26 +547,47 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
|
||||
} else
|
||||
kref_get(&cfid->refcount);
|
||||
}
|
||||
/*
|
||||
* Queue dropping of the dentries once locks have been dropped
|
||||
*/
|
||||
if (!list_empty(&cfids->dying))
|
||||
queue_work(cfid_put_wq, &cfids->invalidation_work);
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
|
||||
list_for_each_entry_safe(cfid, q, &entry, entry) {
|
||||
list_del(&cfid->entry);
|
||||
cancel_work_sync(&cfid->lease_break);
|
||||
/*
|
||||
* Drop the ref-count from above, either the lease-ref (if there
|
||||
* was one) or the extra one acquired.
|
||||
*/
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
smb2_cached_lease_break(struct work_struct *work)
|
||||
cached_dir_offload_close(struct work_struct *work)
|
||||
{
|
||||
struct cached_fid *cfid = container_of(work,
|
||||
struct cached_fid, lease_break);
|
||||
struct cached_fid, close_work);
|
||||
struct cifs_tcon *tcon = cfid->tcon;
|
||||
|
||||
WARN_ON(cfid->on_list);
|
||||
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cached_close);
|
||||
}
|
||||
|
||||
/*
|
||||
* Release the cached directory's dentry, and then queue work to drop cached
|
||||
* directory itself (closing on server if needed).
|
||||
*
|
||||
* Must be called with a reference to the cached_fid and a reference to the
|
||||
* tcon.
|
||||
*/
|
||||
static void cached_dir_put_work(struct work_struct *work)
|
||||
{
|
||||
struct cached_fid *cfid = container_of(work, struct cached_fid,
|
||||
put_work);
|
||||
struct dentry *dentry;
|
||||
|
||||
spin_lock(&cfid->fid_lock);
|
||||
dentry = cfid->dentry;
|
||||
cfid->dentry = NULL;
|
||||
spin_unlock(&cfid->fid_lock);
|
||||
|
||||
dput(dentry);
|
||||
queue_work(serverclose_wq, &cfid->close_work);
|
||||
}
|
||||
|
||||
int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
|
||||
@ -560,8 +614,10 @@ int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
|
||||
cfid->on_list = false;
|
||||
cfids->num_entries--;
|
||||
|
||||
queue_work(cifsiod_wq,
|
||||
&cfid->lease_break);
|
||||
++tcon->tc_count;
|
||||
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
|
||||
netfs_trace_tcon_ref_get_cached_lease_break);
|
||||
queue_work(cfid_put_wq, &cfid->put_work);
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
return true;
|
||||
}
|
||||
@ -583,7 +639,8 @@ static struct cached_fid *init_cached_dir(const char *path)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INIT_WORK(&cfid->lease_break, smb2_cached_lease_break);
|
||||
INIT_WORK(&cfid->close_work, cached_dir_offload_close);
|
||||
INIT_WORK(&cfid->put_work, cached_dir_put_work);
|
||||
INIT_LIST_HEAD(&cfid->entry);
|
||||
INIT_LIST_HEAD(&cfid->dirents.entries);
|
||||
mutex_init(&cfid->dirents.de_mutex);
|
||||
@ -596,6 +653,9 @@ static void free_cached_dir(struct cached_fid *cfid)
|
||||
{
|
||||
struct cached_dirent *dirent, *q;
|
||||
|
||||
WARN_ON(work_pending(&cfid->close_work));
|
||||
WARN_ON(work_pending(&cfid->put_work));
|
||||
|
||||
dput(cfid->dentry);
|
||||
cfid->dentry = NULL;
|
||||
|
||||
@ -613,10 +673,30 @@ static void free_cached_dir(struct cached_fid *cfid)
|
||||
kfree(cfid);
|
||||
}
|
||||
|
||||
static void cfids_invalidation_worker(struct work_struct *work)
|
||||
{
|
||||
struct cached_fids *cfids = container_of(work, struct cached_fids,
|
||||
invalidation_work);
|
||||
struct cached_fid *cfid, *q;
|
||||
LIST_HEAD(entry);
|
||||
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
/* move cfids->dying to the local list */
|
||||
list_cut_before(&entry, &cfids->dying, &cfids->dying);
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
|
||||
list_for_each_entry_safe(cfid, q, &entry, entry) {
|
||||
list_del(&cfid->entry);
|
||||
/* Drop the ref-count acquired in invalidate_all_cached_dirs */
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
}
|
||||
}
|
||||
|
||||
static void cfids_laundromat_worker(struct work_struct *work)
|
||||
{
|
||||
struct cached_fids *cfids;
|
||||
struct cached_fid *cfid, *q;
|
||||
struct dentry *dentry;
|
||||
LIST_HEAD(entry);
|
||||
|
||||
cfids = container_of(work, struct cached_fids, laundromat_work.work);
|
||||
@ -642,18 +722,28 @@ static void cfids_laundromat_worker(struct work_struct *work)
|
||||
|
||||
list_for_each_entry_safe(cfid, q, &entry, entry) {
|
||||
list_del(&cfid->entry);
|
||||
/*
|
||||
* Cancel and wait for the work to finish in case we are racing
|
||||
* with it.
|
||||
*/
|
||||
cancel_work_sync(&cfid->lease_break);
|
||||
/*
|
||||
* Drop the ref-count from above, either the lease-ref (if there
|
||||
* was one) or the extra one acquired.
|
||||
*/
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
|
||||
spin_lock(&cfid->fid_lock);
|
||||
dentry = cfid->dentry;
|
||||
cfid->dentry = NULL;
|
||||
spin_unlock(&cfid->fid_lock);
|
||||
|
||||
dput(dentry);
|
||||
if (cfid->is_open) {
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
++cfid->tcon->tc_count;
|
||||
trace_smb3_tcon_ref(cfid->tcon->debug_id, cfid->tcon->tc_count,
|
||||
netfs_trace_tcon_ref_get_cached_laundromat);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
queue_work(serverclose_wq, &cfid->close_work);
|
||||
} else
|
||||
/*
|
||||
* Drop the ref-count from above, either the lease-ref (if there
|
||||
* was one) or the extra one acquired.
|
||||
*/
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
}
|
||||
queue_delayed_work(cifsiod_wq, &cfids->laundromat_work,
|
||||
queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
|
||||
dir_cache_timeout * HZ);
|
||||
}
|
||||
|
||||
@ -666,9 +756,11 @@ struct cached_fids *init_cached_dirs(void)
|
||||
return NULL;
|
||||
spin_lock_init(&cfids->cfid_list_lock);
|
||||
INIT_LIST_HEAD(&cfids->entries);
|
||||
INIT_LIST_HEAD(&cfids->dying);
|
||||
|
||||
INIT_WORK(&cfids->invalidation_work, cfids_invalidation_worker);
|
||||
INIT_DELAYED_WORK(&cfids->laundromat_work, cfids_laundromat_worker);
|
||||
queue_delayed_work(cifsiod_wq, &cfids->laundromat_work,
|
||||
queue_delayed_work(cfid_put_wq, &cfids->laundromat_work,
|
||||
dir_cache_timeout * HZ);
|
||||
|
||||
return cfids;
|
||||
@ -687,6 +779,7 @@ void free_cached_dirs(struct cached_fids *cfids)
|
||||
return;
|
||||
|
||||
cancel_delayed_work_sync(&cfids->laundromat_work);
|
||||
cancel_work_sync(&cfids->invalidation_work);
|
||||
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
list_for_each_entry_safe(cfid, q, &cfids->entries, entry) {
|
||||
@ -694,6 +787,11 @@ void free_cached_dirs(struct cached_fids *cfids)
|
||||
cfid->is_open = false;
|
||||
list_move(&cfid->entry, &entry);
|
||||
}
|
||||
list_for_each_entry_safe(cfid, q, &cfids->dying, entry) {
|
||||
cfid->on_list = false;
|
||||
cfid->is_open = false;
|
||||
list_move(&cfid->entry, &entry);
|
||||
}
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
|
||||
list_for_each_entry_safe(cfid, q, &entry, entry) {
|
||||
|
@ -44,7 +44,8 @@ struct cached_fid {
|
||||
spinlock_t fid_lock;
|
||||
struct cifs_tcon *tcon;
|
||||
struct dentry *dentry;
|
||||
struct work_struct lease_break;
|
||||
struct work_struct put_work;
|
||||
struct work_struct close_work;
|
||||
struct smb2_file_all_info file_all_info;
|
||||
struct cached_dirents dirents;
|
||||
};
|
||||
@ -53,10 +54,13 @@ struct cached_fid {
|
||||
struct cached_fids {
|
||||
/* Must be held when:
|
||||
* - accessing the cfids->entries list
|
||||
* - accessing the cfids->dying list
|
||||
*/
|
||||
spinlock_t cfid_list_lock;
|
||||
int num_entries;
|
||||
struct list_head entries;
|
||||
struct list_head dying;
|
||||
struct work_struct invalidation_work;
|
||||
struct delayed_work laundromat_work;
|
||||
};
|
||||
|
||||
|
@ -157,6 +157,7 @@ struct workqueue_struct *fileinfo_put_wq;
|
||||
struct workqueue_struct *cifsoplockd_wq;
|
||||
struct workqueue_struct *deferredclose_wq;
|
||||
struct workqueue_struct *serverclose_wq;
|
||||
struct workqueue_struct *cfid_put_wq;
|
||||
__u32 cifs_lock_secret;
|
||||
|
||||
/*
|
||||
@ -1920,9 +1921,16 @@ init_cifs(void)
|
||||
goto out_destroy_deferredclose_wq;
|
||||
}
|
||||
|
||||
cfid_put_wq = alloc_workqueue("cfid_put_wq",
|
||||
WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
|
||||
if (!cfid_put_wq) {
|
||||
rc = -ENOMEM;
|
||||
goto out_destroy_serverclose_wq;
|
||||
}
|
||||
|
||||
rc = cifs_init_inodecache();
|
||||
if (rc)
|
||||
goto out_destroy_serverclose_wq;
|
||||
goto out_destroy_cfid_put_wq;
|
||||
|
||||
rc = cifs_init_netfs();
|
||||
if (rc)
|
||||
@ -1990,6 +1998,8 @@ init_cifs(void)
|
||||
cifs_destroy_netfs();
|
||||
out_destroy_inodecache:
|
||||
cifs_destroy_inodecache();
|
||||
out_destroy_cfid_put_wq:
|
||||
destroy_workqueue(cfid_put_wq);
|
||||
out_destroy_serverclose_wq:
|
||||
destroy_workqueue(serverclose_wq);
|
||||
out_destroy_deferredclose_wq:
|
||||
|
@ -146,6 +146,6 @@ extern const struct export_operations cifs_export_ops;
|
||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||
|
||||
/* when changing internal version - update following two lines at same time */
|
||||
#define SMB3_PRODUCT_BUILD 51
|
||||
#define CIFS_VERSION "2.51"
|
||||
#define SMB3_PRODUCT_BUILD 52
|
||||
#define CIFS_VERSION "2.52"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
@ -594,6 +594,7 @@ struct smb_version_operations {
|
||||
/* Check for STATUS_NETWORK_NAME_DELETED */
|
||||
bool (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv);
|
||||
int (*parse_reparse_point)(struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct kvec *rsp_iov,
|
||||
struct cifs_open_info_data *data);
|
||||
int (*create_reparse_symlink)(const unsigned int xid,
|
||||
@ -1990,7 +1991,7 @@ require use of the stronger protocol */
|
||||
* cifsInodeInfo->lock_sem cifsInodeInfo->llist cifs_init_once
|
||||
* ->can_cache_brlcks
|
||||
* cifsInodeInfo->deferred_lock cifsInodeInfo->deferred_closes cifsInodeInfo_alloc
|
||||
* cached_fid->fid_mutex cifs_tcon->crfid tcon_info_alloc
|
||||
* cached_fids->cfid_list_lock cifs_tcon->cfids->entries init_cached_dirs
|
||||
* cifsFileInfo->fh_mutex cifsFileInfo cifs_new_fileinfo
|
||||
* cifsFileInfo->file_info_lock cifsFileInfo->count cifs_new_fileinfo
|
||||
* ->invalidHandle initiate_cifs_search
|
||||
@ -2078,6 +2079,7 @@ extern struct workqueue_struct *fileinfo_put_wq;
|
||||
extern struct workqueue_struct *cifsoplockd_wq;
|
||||
extern struct workqueue_struct *deferredclose_wq;
|
||||
extern struct workqueue_struct *serverclose_wq;
|
||||
extern struct workqueue_struct *cfid_put_wq;
|
||||
extern __u32 cifs_lock_secret;
|
||||
|
||||
extern mempool_t *cifs_sm_req_poolp;
|
||||
|
@ -314,8 +314,7 @@ extern void cifs_move_llist(struct list_head *source, struct list_head *dest);
|
||||
extern void cifs_free_llist(struct list_head *llist);
|
||||
extern void cifs_del_lock_waiters(struct cifsLockInfo *lock);
|
||||
|
||||
extern int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const struct nls_table *nlsc);
|
||||
int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon);
|
||||
|
||||
extern int cifs_negotiate_protocol(const unsigned int xid,
|
||||
struct cifs_ses *ses,
|
||||
@ -661,6 +660,7 @@ char *extract_hostname(const char *unc);
|
||||
char *extract_sharename(const char *unc);
|
||||
int parse_reparse_point(struct reparse_data_buffer *buf,
|
||||
u32 plen, struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
bool unicode, struct cifs_open_info_data *data);
|
||||
int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
|
||||
struct dentry *dentry, struct cifs_tcon *tcon,
|
||||
|
@ -70,10 +70,9 @@ static struct {
|
||||
static int
|
||||
cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
||||
{
|
||||
int rc;
|
||||
struct cifs_ses *ses;
|
||||
struct TCP_Server_Info *server;
|
||||
struct nls_table *nls_codepage = NULL;
|
||||
struct cifs_ses *ses;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
|
||||
@ -131,8 +130,6 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
||||
}
|
||||
spin_unlock(&server->srv_lock);
|
||||
|
||||
nls_codepage = ses->local_nls;
|
||||
|
||||
/*
|
||||
* need to prevent multiple threads trying to simultaneously
|
||||
* reconnect the same SMB session
|
||||
@ -156,7 +153,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
||||
|
||||
rc = cifs_negotiate_protocol(0, ses, server);
|
||||
if (!rc)
|
||||
rc = cifs_setup_session(0, ses, server, nls_codepage);
|
||||
rc = cifs_setup_session(0, ses, server, ses->local_nls);
|
||||
|
||||
/* do we need to reconnect tcon? */
|
||||
if (rc || !tcon->need_reconnect) {
|
||||
@ -166,7 +163,7 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
|
||||
|
||||
skip_sess_setup:
|
||||
cifs_mark_open_files_invalid(tcon);
|
||||
rc = cifs_tree_connect(0, tcon, nls_codepage);
|
||||
rc = cifs_tree_connect(0, tcon);
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
|
||||
|
||||
@ -4320,8 +4317,8 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
|
||||
* CIFSGetDFSRefer() may be called from cifs_reconnect_tcon() and thus
|
||||
* causing an infinite recursion.
|
||||
*/
|
||||
rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc,
|
||||
(void **)&pSMB, (void **)&pSMBr);
|
||||
rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc,
|
||||
(void **)&pSMB, (void **)&pSMBr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -1897,11 +1897,35 @@ static int match_session(struct cifs_ses *ses,
|
||||
CIFS_MAX_USERNAME_LEN))
|
||||
return 0;
|
||||
if ((ctx->username && strlen(ctx->username) != 0) &&
|
||||
ses->password != NULL &&
|
||||
strncmp(ses->password,
|
||||
ctx->password ? ctx->password : "",
|
||||
CIFS_MAX_PASSWORD_LEN))
|
||||
return 0;
|
||||
ses->password != NULL) {
|
||||
|
||||
/* New mount can only share sessions with an existing mount if:
|
||||
* 1. Both password and password2 match, or
|
||||
* 2. password2 of the old mount matches password of the new mount
|
||||
* and password of the old mount matches password2 of the new
|
||||
* mount
|
||||
*/
|
||||
if (ses->password2 != NULL && ctx->password2 != NULL) {
|
||||
if (!((strncmp(ses->password, ctx->password ?
|
||||
ctx->password : "", CIFS_MAX_PASSWORD_LEN) == 0 &&
|
||||
strncmp(ses->password2, ctx->password2,
|
||||
CIFS_MAX_PASSWORD_LEN) == 0) ||
|
||||
(strncmp(ses->password, ctx->password2,
|
||||
CIFS_MAX_PASSWORD_LEN) == 0 &&
|
||||
strncmp(ses->password2, ctx->password ?
|
||||
ctx->password : "", CIFS_MAX_PASSWORD_LEN) == 0)))
|
||||
return 0;
|
||||
|
||||
} else if ((ses->password2 == NULL && ctx->password2 != NULL) ||
|
||||
(ses->password2 != NULL && ctx->password2 == NULL)) {
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
if (strncmp(ses->password, ctx->password ?
|
||||
ctx->password : "", CIFS_MAX_PASSWORD_LEN))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(ctx->local_nls->charset, ses->local_nls->charset))
|
||||
@ -2244,6 +2268,7 @@ struct cifs_ses *
|
||||
cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
|
||||
{
|
||||
int rc = 0;
|
||||
int retries = 0;
|
||||
unsigned int xid;
|
||||
struct cifs_ses *ses;
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr;
|
||||
@ -2262,6 +2287,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
|
||||
cifs_dbg(FYI, "Session needs reconnect\n");
|
||||
|
||||
mutex_lock(&ses->session_mutex);
|
||||
|
||||
retry_old_session:
|
||||
rc = cifs_negotiate_protocol(xid, ses, server);
|
||||
if (rc) {
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
@ -2274,6 +2301,13 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
|
||||
rc = cifs_setup_session(xid, ses, server,
|
||||
ctx->local_nls);
|
||||
if (rc) {
|
||||
if (((rc == -EACCES) || (rc == -EKEYEXPIRED) ||
|
||||
(rc == -EKEYREVOKED)) && !retries && ses->password2) {
|
||||
retries++;
|
||||
cifs_dbg(FYI, "Session reconnect failed, retrying with alternate password\n");
|
||||
swap(ses->password, ses->password2);
|
||||
goto retry_old_session;
|
||||
}
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
/* problem -- put our reference */
|
||||
cifs_put_smb_ses(ses);
|
||||
@ -2369,6 +2403,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
|
||||
ses->chans_need_reconnect = 1;
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
retry_new_session:
|
||||
mutex_lock(&ses->session_mutex);
|
||||
rc = cifs_negotiate_protocol(xid, ses, server);
|
||||
if (!rc)
|
||||
@ -2381,8 +2416,16 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
|
||||
sizeof(ses->smb3signingkey));
|
||||
spin_unlock(&ses->chan_lock);
|
||||
|
||||
if (rc)
|
||||
goto get_ses_fail;
|
||||
if (rc) {
|
||||
if (((rc == -EACCES) || (rc == -EKEYEXPIRED) ||
|
||||
(rc == -EKEYREVOKED)) && !retries && ses->password2) {
|
||||
retries++;
|
||||
cifs_dbg(FYI, "Session setup failed, retrying with alternate password\n");
|
||||
swap(ses->password, ses->password2);
|
||||
goto retry_new_session;
|
||||
} else
|
||||
goto get_ses_fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* success, put it on the list and add it as first channel
|
||||
@ -2571,7 +2614,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
|
||||
|
||||
if (ses->server->dialect >= SMB20_PROT_ID &&
|
||||
(ses->server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING))
|
||||
nohandlecache = ctx->nohandlecache;
|
||||
nohandlecache = ctx->nohandlecache || !dir_cache_timeout;
|
||||
else
|
||||
nohandlecache = true;
|
||||
tcon = tcon_info_alloc(!nohandlecache, netfs_trace_tcon_ref_new);
|
||||
@ -4344,10 +4387,10 @@ cifs_prune_tlinks(struct work_struct *work)
|
||||
}
|
||||
|
||||
#ifndef CONFIG_CIFS_DFS_UPCALL
|
||||
int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc)
|
||||
int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon)
|
||||
{
|
||||
int rc;
|
||||
const struct smb_version_operations *ops = tcon->ses->server->ops;
|
||||
int rc;
|
||||
|
||||
/* only send once per connect */
|
||||
spin_lock(&tcon->tc_lock);
|
||||
@ -4370,7 +4413,8 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
|
||||
tcon->status = TID_IN_TCON;
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
|
||||
rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, tcon, nlsc);
|
||||
rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name,
|
||||
tcon, tcon->ses->local_nls);
|
||||
if (rc) {
|
||||
spin_lock(&tcon->tc_lock);
|
||||
if (tcon->status == TID_IN_TCON)
|
||||
|
@ -321,49 +321,6 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Update dfs referral path of superblock */
|
||||
static int update_server_fullpath(struct TCP_Server_Info *server, struct cifs_sb_info *cifs_sb,
|
||||
const char *target)
|
||||
{
|
||||
int rc = 0;
|
||||
size_t len = strlen(target);
|
||||
char *refpath, *npath;
|
||||
|
||||
if (unlikely(len < 2 || *target != '\\'))
|
||||
return -EINVAL;
|
||||
|
||||
if (target[1] == '\\') {
|
||||
len += 1;
|
||||
refpath = kmalloc(len, GFP_KERNEL);
|
||||
if (!refpath)
|
||||
return -ENOMEM;
|
||||
|
||||
scnprintf(refpath, len, "%s", target);
|
||||
} else {
|
||||
len += sizeof("\\");
|
||||
refpath = kmalloc(len, GFP_KERNEL);
|
||||
if (!refpath)
|
||||
return -ENOMEM;
|
||||
|
||||
scnprintf(refpath, len, "\\%s", target);
|
||||
}
|
||||
|
||||
npath = dfs_cache_canonical_path(refpath, cifs_sb->local_nls, cifs_remap(cifs_sb));
|
||||
kfree(refpath);
|
||||
|
||||
if (IS_ERR(npath)) {
|
||||
rc = PTR_ERR(npath);
|
||||
} else {
|
||||
mutex_lock(&server->refpath_lock);
|
||||
spin_lock(&server->srv_lock);
|
||||
kfree(server->leaf_fullpath);
|
||||
server->leaf_fullpath = npath;
|
||||
spin_unlock(&server->srv_lock);
|
||||
mutex_unlock(&server->refpath_lock);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int target_share_matches_server(struct TCP_Server_Info *server, char *share,
|
||||
bool *target_match)
|
||||
{
|
||||
@ -388,77 +345,22 @@ static int target_share_matches_server(struct TCP_Server_Info *server, char *sha
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __tree_connect_ipc(const unsigned int xid, char *tree,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_ses *ses)
|
||||
static int tree_connect_dfs_target(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
char *tree, bool islink,
|
||||
struct dfs_cache_tgt_list *tl)
|
||||
{
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
struct cifs_tcon *tcon = ses->tcon_ipc;
|
||||
int rc;
|
||||
|
||||
spin_lock(&ses->ses_lock);
|
||||
spin_lock(&ses->chan_lock);
|
||||
if (cifs_chan_needs_reconnect(ses, server) ||
|
||||
ses->ses_status != SES_GOOD) {
|
||||
spin_unlock(&ses->chan_lock);
|
||||
spin_unlock(&ses->ses_lock);
|
||||
cifs_server_dbg(FYI, "%s: skipping ipc reconnect due to disconnected ses\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
spin_unlock(&ses->chan_lock);
|
||||
spin_unlock(&ses->ses_lock);
|
||||
|
||||
cifs_server_lock(server);
|
||||
scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname);
|
||||
cifs_server_unlock(server);
|
||||
|
||||
rc = server->ops->tree_connect(xid, ses, tree, tcon,
|
||||
cifs_sb->local_nls);
|
||||
cifs_server_dbg(FYI, "%s: tree_reconnect %s: %d\n", __func__, tree, rc);
|
||||
spin_lock(&tcon->tc_lock);
|
||||
if (rc) {
|
||||
tcon->status = TID_NEED_TCON;
|
||||
} else {
|
||||
tcon->status = TID_GOOD;
|
||||
tcon->need_reconnect = false;
|
||||
}
|
||||
spin_unlock(&tcon->tc_lock);
|
||||
}
|
||||
|
||||
static void tree_connect_ipc(const unsigned int xid, char *tree,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_tcon *tcon)
|
||||
{
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
|
||||
__tree_connect_ipc(xid, tree, cifs_sb, ses);
|
||||
__tree_connect_ipc(xid, tree, cifs_sb, CIFS_DFS_ROOT_SES(ses));
|
||||
}
|
||||
|
||||
static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, char *tree, bool islink,
|
||||
struct dfs_cache_tgt_list *tl)
|
||||
{
|
||||
int rc;
|
||||
const struct smb_version_operations *ops = tcon->ses->server->ops;
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
const struct smb_version_operations *ops = server->ops;
|
||||
struct cifs_ses *root_ses = CIFS_DFS_ROOT_SES(tcon->ses);
|
||||
char *share = NULL, *prefix = NULL;
|
||||
struct dfs_cache_tgt_iterator *tit;
|
||||
char *share = NULL, *prefix = NULL;
|
||||
bool target_match;
|
||||
|
||||
tit = dfs_cache_get_tgt_iterator(tl);
|
||||
if (!tit) {
|
||||
rc = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
int rc = -ENOENT;
|
||||
|
||||
/* Try to tree connect to all dfs targets */
|
||||
for (; tit; tit = dfs_cache_get_next_tgt(tl, tit)) {
|
||||
const char *target = dfs_cache_get_tgt_name(tit);
|
||||
DFS_CACHE_TGT_LIST(ntl);
|
||||
|
||||
for (tit = dfs_cache_get_tgt_iterator(tl);
|
||||
tit; tit = dfs_cache_get_next_tgt(tl, tit)) {
|
||||
kfree(share);
|
||||
kfree(prefix);
|
||||
share = prefix = NULL;
|
||||
@ -479,74 +381,21 @@ static int __tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *t
|
||||
}
|
||||
|
||||
dfs_cache_noreq_update_tgthint(server->leaf_fullpath + 1, tit);
|
||||
tree_connect_ipc(xid, tree, cifs_sb, tcon);
|
||||
|
||||
scnprintf(tree, MAX_TREE_SIZE, "\\%s", share);
|
||||
if (!islink) {
|
||||
rc = ops->tree_connect(xid, tcon->ses, tree, tcon, cifs_sb->local_nls);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If no dfs referrals were returned from link target, then just do a TREE_CONNECT
|
||||
* to it. Otherwise, cache the dfs referral and then mark current tcp ses for
|
||||
* reconnect so either the demultiplex thread or the echo worker will reconnect to
|
||||
* newly resolved target.
|
||||
*/
|
||||
if (dfs_cache_find(xid, root_ses, cifs_sb->local_nls, cifs_remap(cifs_sb), target,
|
||||
NULL, &ntl)) {
|
||||
rc = ops->tree_connect(xid, tcon->ses, tree, tcon, cifs_sb->local_nls);
|
||||
if (rc)
|
||||
continue;
|
||||
|
||||
rc = ops->tree_connect(xid, tcon->ses, tree,
|
||||
tcon, tcon->ses->local_nls);
|
||||
if (islink && !rc && cifs_sb)
|
||||
rc = cifs_update_super_prepath(cifs_sb, prefix);
|
||||
} else {
|
||||
/* Target is another dfs share */
|
||||
rc = update_server_fullpath(server, cifs_sb, target);
|
||||
dfs_cache_free_tgts(tl);
|
||||
|
||||
if (!rc) {
|
||||
rc = -EREMOTE;
|
||||
list_replace_init(&ntl.tl_list, &tl->tl_list);
|
||||
} else
|
||||
dfs_cache_free_tgts(&ntl);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(share);
|
||||
kfree(prefix);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int tree_connect_dfs_target(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb, char *tree, bool islink,
|
||||
struct dfs_cache_tgt_list *tl)
|
||||
{
|
||||
int rc;
|
||||
int num_links = 0;
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
char *old_fullpath = server->leaf_fullpath;
|
||||
|
||||
do {
|
||||
rc = __tree_connect_dfs_target(xid, tcon, cifs_sb, tree, islink, tl);
|
||||
if (!rc || rc != -EREMOTE)
|
||||
break;
|
||||
} while (rc = -ELOOP, ++num_links < MAX_NESTED_LINKS);
|
||||
/*
|
||||
* If we couldn't tree connect to any targets from last referral path, then
|
||||
* retry it from newly resolved dfs referral.
|
||||
*/
|
||||
if (rc && server->leaf_fullpath != old_fullpath)
|
||||
cifs_signal_cifsd_for_reconnect(server, true);
|
||||
|
||||
dfs_cache_free_tgts(tl);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const struct nls_table *nlsc)
|
||||
int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon)
|
||||
{
|
||||
int rc;
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
@ -588,7 +437,8 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
|
||||
cifs_server_lock(server);
|
||||
scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", server->hostname);
|
||||
cifs_server_unlock(server);
|
||||
rc = ops->tree_connect(xid, tcon->ses, tree, tcon, nlsc);
|
||||
rc = ops->tree_connect(xid, tcon->ses, tree,
|
||||
tcon, tcon->ses->local_nls);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -596,14 +446,11 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
|
||||
if (!IS_ERR(sb))
|
||||
cifs_sb = CIFS_SB(sb);
|
||||
|
||||
/*
|
||||
* Tree connect to last share in @tcon->tree_name whether dfs super or
|
||||
* cached dfs referral was not found.
|
||||
*/
|
||||
if (!cifs_sb || !server->leaf_fullpath ||
|
||||
/* Tree connect to last share in @tcon->tree_name if no DFS referral */
|
||||
if (!server->leaf_fullpath ||
|
||||
dfs_cache_noreq_find(server->leaf_fullpath + 1, &ref, &tl)) {
|
||||
rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, tcon,
|
||||
cifs_sb ? cifs_sb->local_nls : nlsc);
|
||||
rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name,
|
||||
tcon, tcon->ses->local_nls);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,8 @@
|
||||
|
||||
#include "dfs_cache.h"
|
||||
|
||||
#define CACHE_HTABLE_SIZE 32
|
||||
#define CACHE_MAX_ENTRIES 64
|
||||
#define CACHE_HTABLE_SIZE 512
|
||||
#define CACHE_MAX_ENTRIES 1024
|
||||
#define CACHE_MIN_TTL 120 /* 2 minutes */
|
||||
#define CACHE_DEFAULT_TTL 300 /* 5 minutes */
|
||||
|
||||
|
@ -920,12 +920,37 @@ do { \
|
||||
cifs_sb->ctx->field = NULL; \
|
||||
} while (0)
|
||||
|
||||
int smb3_sync_session_ctx_passwords(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses)
|
||||
{
|
||||
if (ses->password &&
|
||||
cifs_sb->ctx->password &&
|
||||
strcmp(ses->password, cifs_sb->ctx->password)) {
|
||||
kfree_sensitive(cifs_sb->ctx->password);
|
||||
cifs_sb->ctx->password = kstrdup(ses->password, GFP_KERNEL);
|
||||
if (!cifs_sb->ctx->password)
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (ses->password2 &&
|
||||
cifs_sb->ctx->password2 &&
|
||||
strcmp(ses->password2, cifs_sb->ctx->password2)) {
|
||||
kfree_sensitive(cifs_sb->ctx->password2);
|
||||
cifs_sb->ctx->password2 = kstrdup(ses->password2, GFP_KERNEL);
|
||||
if (!cifs_sb->ctx->password2) {
|
||||
kfree_sensitive(cifs_sb->ctx->password);
|
||||
cifs_sb->ctx->password = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smb3_reconfigure(struct fs_context *fc)
|
||||
{
|
||||
struct smb3_fs_context *ctx = smb3_fc2context(fc);
|
||||
struct dentry *root = fc->root;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(root->d_sb);
|
||||
struct cifs_ses *ses = cifs_sb_master_tcon(cifs_sb)->ses;
|
||||
char *new_password = NULL, *new_password2 = NULL;
|
||||
bool need_recon = false;
|
||||
int rc;
|
||||
|
||||
@ -945,21 +970,63 @@ static int smb3_reconfigure(struct fs_context *fc)
|
||||
STEAL_STRING(cifs_sb, ctx, UNC);
|
||||
STEAL_STRING(cifs_sb, ctx, source);
|
||||
STEAL_STRING(cifs_sb, ctx, username);
|
||||
|
||||
if (need_recon == false)
|
||||
STEAL_STRING_SENSITIVE(cifs_sb, ctx, password);
|
||||
else {
|
||||
kfree_sensitive(ses->password);
|
||||
ses->password = kstrdup(ctx->password, GFP_KERNEL);
|
||||
if (!ses->password)
|
||||
return -ENOMEM;
|
||||
kfree_sensitive(ses->password2);
|
||||
ses->password2 = kstrdup(ctx->password2, GFP_KERNEL);
|
||||
if (!ses->password2) {
|
||||
kfree_sensitive(ses->password);
|
||||
ses->password = NULL;
|
||||
if (ctx->password) {
|
||||
new_password = kstrdup(ctx->password, GFP_KERNEL);
|
||||
if (!new_password)
|
||||
return -ENOMEM;
|
||||
} else
|
||||
STEAL_STRING_SENSITIVE(cifs_sb, ctx, password);
|
||||
}
|
||||
|
||||
/*
|
||||
* if a new password2 has been specified, then reset it's value
|
||||
* inside the ses struct
|
||||
*/
|
||||
if (ctx->password2) {
|
||||
new_password2 = kstrdup(ctx->password2, GFP_KERNEL);
|
||||
if (!new_password2) {
|
||||
kfree_sensitive(new_password);
|
||||
return -ENOMEM;
|
||||
}
|
||||
} else
|
||||
STEAL_STRING_SENSITIVE(cifs_sb, ctx, password2);
|
||||
|
||||
/*
|
||||
* we may update the passwords in the ses struct below. Make sure we do
|
||||
* not race with smb2_reconnect
|
||||
*/
|
||||
mutex_lock(&ses->session_mutex);
|
||||
|
||||
/*
|
||||
* smb2_reconnect may swap password and password2 in case session setup
|
||||
* failed. First get ctx passwords in sync with ses passwords. It should
|
||||
* be okay to do this even if this function were to return an error at a
|
||||
* later stage
|
||||
*/
|
||||
rc = smb3_sync_session_ctx_passwords(cifs_sb, ses);
|
||||
if (rc) {
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* now that allocations for passwords are done, commit them
|
||||
*/
|
||||
if (new_password) {
|
||||
kfree_sensitive(ses->password);
|
||||
ses->password = new_password;
|
||||
}
|
||||
if (new_password2) {
|
||||
kfree_sensitive(ses->password2);
|
||||
ses->password2 = new_password2;
|
||||
}
|
||||
|
||||
mutex_unlock(&ses->session_mutex);
|
||||
|
||||
STEAL_STRING(cifs_sb, ctx, domainname);
|
||||
STEAL_STRING(cifs_sb, ctx, nodename);
|
||||
STEAL_STRING(cifs_sb, ctx, iocharset);
|
||||
|
@ -309,6 +309,7 @@ static inline struct smb3_fs_context *smb3_fc2context(const struct fs_context *f
|
||||
}
|
||||
|
||||
extern int smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx);
|
||||
extern int smb3_sync_session_ctx_passwords(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses);
|
||||
extern void smb3_update_mnt_flags(struct cifs_sb_info *cifs_sb);
|
||||
|
||||
/*
|
||||
|
@ -1137,6 +1137,7 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
|
||||
rc = 0;
|
||||
} else if (iov && server->ops->parse_reparse_point) {
|
||||
rc = server->ops->parse_reparse_point(cifs_sb,
|
||||
full_path,
|
||||
iov, data);
|
||||
}
|
||||
break;
|
||||
@ -2495,13 +2496,10 @@ cifs_dentry_needs_reval(struct dentry *dentry)
|
||||
return true;
|
||||
|
||||
if (!open_cached_dir_by_dentry(tcon, dentry->d_parent, &cfid)) {
|
||||
spin_lock(&cfid->fid_lock);
|
||||
if (cfid->time && cifs_i->time > cfid->time) {
|
||||
spin_unlock(&cfid->fid_lock);
|
||||
close_cached_dir(cfid);
|
||||
return false;
|
||||
}
|
||||
spin_unlock(&cfid->fid_lock);
|
||||
close_cached_dir(cfid);
|
||||
}
|
||||
/*
|
||||
|
@ -378,8 +378,8 @@ static int wsl_set_xattrs(struct inode *inode, umode_t _mode,
|
||||
|
||||
memset(iov, 0, sizeof(*iov));
|
||||
|
||||
/* Exclude $LXDEV xattr for sockets and fifos */
|
||||
if (S_ISSOCK(_mode) || S_ISFIFO(_mode))
|
||||
/* Exclude $LXDEV xattr for non-device files */
|
||||
if (!S_ISBLK(_mode) && !S_ISCHR(_mode))
|
||||
num_xattrs = ARRAY_SIZE(xattrs) - 1;
|
||||
else
|
||||
num_xattrs = ARRAY_SIZE(xattrs);
|
||||
@ -535,9 +535,95 @@ static int parse_reparse_posix(struct reparse_posix_data *buf,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
|
||||
bool unicode, bool relative,
|
||||
const char *full_path,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
char sep = CIFS_DIR_SEP(cifs_sb);
|
||||
char *linux_target = NULL;
|
||||
char *smb_target = NULL;
|
||||
int levels;
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
/* Check that length it valid for unicode/non-unicode mode */
|
||||
if (!len || (unicode && (len % 2))) {
|
||||
cifs_dbg(VFS, "srv returned malformed symlink buffer\n");
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that buffer does not contain UTF-16 null codepoint in unicode
|
||||
* mode or null byte in non-unicode mode because Linux cannot process
|
||||
* symlink with null byte.
|
||||
*/
|
||||
if ((unicode && UniStrnlen((wchar_t *)buf, len/2) != len/2) ||
|
||||
(!unicode && strnlen(buf, len) != len)) {
|
||||
cifs_dbg(VFS, "srv returned null byte in native symlink target location\n");
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
smb_target = cifs_strndup_from_utf16(buf, len, unicode, cifs_sb->local_nls);
|
||||
if (!smb_target) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (smb_target[0] == sep && relative) {
|
||||
/*
|
||||
* This is a relative SMB symlink from the top of the share,
|
||||
* which is the top level directory of the Linux mount point.
|
||||
* Linux does not support such relative symlinks, so convert
|
||||
* it to the relative symlink from the current directory.
|
||||
* full_path is the SMB path to the symlink (from which is
|
||||
* extracted current directory) and smb_target is the SMB path
|
||||
* where symlink points, therefore full_path must always be on
|
||||
* the SMB share.
|
||||
*/
|
||||
int smb_target_len = strlen(smb_target)+1;
|
||||
levels = 0;
|
||||
for (i = 1; full_path[i]; i++) { /* i=1 to skip leading sep */
|
||||
if (full_path[i] == sep)
|
||||
levels++;
|
||||
}
|
||||
linux_target = kmalloc(levels*3 + smb_target_len, GFP_KERNEL);
|
||||
if (!linux_target) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < levels; i++) {
|
||||
linux_target[i*3 + 0] = '.';
|
||||
linux_target[i*3 + 1] = '.';
|
||||
linux_target[i*3 + 2] = sep;
|
||||
}
|
||||
memcpy(linux_target + levels*3, smb_target+1, smb_target_len); /* +1 to skip leading sep */
|
||||
} else {
|
||||
linux_target = smb_target;
|
||||
smb_target = NULL;
|
||||
}
|
||||
|
||||
if (sep == '\\')
|
||||
convert_delimiter(linux_target, '/');
|
||||
|
||||
rc = 0;
|
||||
*target = linux_target;
|
||||
|
||||
cifs_dbg(FYI, "%s: symlink target: %s\n", __func__, *target);
|
||||
|
||||
out:
|
||||
if (rc != 0)
|
||||
kfree(linux_target);
|
||||
kfree(smb_target);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym,
|
||||
u32 plen, bool unicode,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct cifs_open_info_data *data)
|
||||
{
|
||||
unsigned int len;
|
||||
@ -552,20 +638,64 @@ static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
data->symlink_target = cifs_strndup_from_utf16(sym->PathBuffer + offs,
|
||||
len, unicode,
|
||||
return smb2_parse_native_symlink(&data->symlink_target,
|
||||
sym->PathBuffer + offs,
|
||||
len,
|
||||
unicode,
|
||||
le32_to_cpu(sym->Flags) & SYMLINK_FLAG_RELATIVE,
|
||||
full_path,
|
||||
cifs_sb);
|
||||
}
|
||||
|
||||
static int parse_reparse_wsl_symlink(struct reparse_wsl_symlink_data_buffer *buf,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_open_info_data *data)
|
||||
{
|
||||
int len = le16_to_cpu(buf->ReparseDataLength);
|
||||
int symname_utf8_len;
|
||||
__le16 *symname_utf16;
|
||||
int symname_utf16_len;
|
||||
|
||||
if (len <= sizeof(buf->Flags)) {
|
||||
cifs_dbg(VFS, "srv returned malformed wsl symlink buffer\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* PathBuffer is in UTF-8 but without trailing null-term byte */
|
||||
symname_utf8_len = len - sizeof(buf->Flags);
|
||||
/*
|
||||
* Check that buffer does not contain null byte
|
||||
* because Linux cannot process symlink with null byte.
|
||||
*/
|
||||
if (strnlen(buf->PathBuffer, symname_utf8_len) != symname_utf8_len) {
|
||||
cifs_dbg(VFS, "srv returned null byte in wsl symlink target location\n");
|
||||
return -EIO;
|
||||
}
|
||||
symname_utf16 = kzalloc(symname_utf8_len * 2, GFP_KERNEL);
|
||||
if (!symname_utf16)
|
||||
return -ENOMEM;
|
||||
symname_utf16_len = utf8s_to_utf16s(buf->PathBuffer, symname_utf8_len,
|
||||
UTF16_LITTLE_ENDIAN,
|
||||
symname_utf16, symname_utf8_len * 2);
|
||||
if (symname_utf16_len < 0) {
|
||||
kfree(symname_utf16);
|
||||
return symname_utf16_len;
|
||||
}
|
||||
symname_utf16_len *= 2; /* utf8s_to_utf16s() returns number of u16 items, not byte length */
|
||||
|
||||
data->symlink_target = cifs_strndup_from_utf16((u8 *)symname_utf16,
|
||||
symname_utf16_len, true,
|
||||
cifs_sb->local_nls);
|
||||
kfree(symname_utf16);
|
||||
if (!data->symlink_target)
|
||||
return -ENOMEM;
|
||||
|
||||
convert_delimiter(data->symlink_target, '/');
|
||||
cifs_dbg(FYI, "%s: target path: %s\n", __func__, data->symlink_target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_reparse_point(struct reparse_data_buffer *buf,
|
||||
u32 plen, struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
bool unicode, struct cifs_open_info_data *data)
|
||||
{
|
||||
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
@ -580,12 +710,20 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
|
||||
case IO_REPARSE_TAG_SYMLINK:
|
||||
return parse_reparse_symlink(
|
||||
(struct reparse_symlink_data_buffer *)buf,
|
||||
plen, unicode, cifs_sb, data);
|
||||
plen, unicode, cifs_sb, full_path, data);
|
||||
case IO_REPARSE_TAG_LX_SYMLINK:
|
||||
return parse_reparse_wsl_symlink(
|
||||
(struct reparse_wsl_symlink_data_buffer *)buf,
|
||||
cifs_sb, data);
|
||||
case IO_REPARSE_TAG_AF_UNIX:
|
||||
case IO_REPARSE_TAG_LX_FIFO:
|
||||
case IO_REPARSE_TAG_LX_CHR:
|
||||
case IO_REPARSE_TAG_LX_BLK:
|
||||
if (le16_to_cpu(buf->ReparseDataLength) != 0) {
|
||||
cifs_dbg(VFS, "srv returned malformed buffer for reparse point: 0x%08x\n",
|
||||
le32_to_cpu(buf->ReparseTag));
|
||||
return -EIO;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cifs_tcon_dbg(VFS | ONCE, "unhandled reparse tag: 0x%08x\n",
|
||||
@ -596,6 +734,7 @@ int parse_reparse_point(struct reparse_data_buffer *buf,
|
||||
}
|
||||
|
||||
int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct kvec *rsp_iov,
|
||||
struct cifs_open_info_data *data)
|
||||
{
|
||||
@ -605,7 +744,7 @@ int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
|
||||
|
||||
buf = (struct reparse_data_buffer *)((u8 *)io +
|
||||
le32_to_cpu(io->OutputOffset));
|
||||
return parse_reparse_point(buf, plen, cifs_sb, true, data);
|
||||
return parse_reparse_point(buf, plen, cifs_sb, full_path, true, data);
|
||||
}
|
||||
|
||||
static void wsl_to_fattr(struct cifs_open_info_data *data,
|
||||
|
@ -117,7 +117,9 @@ int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
|
||||
int smb2_mknod_reparse(unsigned int xid, struct inode *inode,
|
||||
struct dentry *dentry, struct cifs_tcon *tcon,
|
||||
const char *full_path, umode_t mode, dev_t dev);
|
||||
int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb, struct kvec *rsp_iov,
|
||||
int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct kvec *rsp_iov,
|
||||
struct cifs_open_info_data *data);
|
||||
|
||||
#endif /* _CIFS_REPARSE_H */
|
||||
|
@ -347,10 +347,7 @@ cifs_disable_secondary_channels(struct cifs_ses *ses)
|
||||
spin_unlock(&ses->chan_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* update the iface for the channel if necessary.
|
||||
* Must be called with chan_lock held.
|
||||
*/
|
||||
/* update the iface for the channel if necessary. */
|
||||
void
|
||||
cifs_chan_update_iface(struct cifs_ses *ses, struct TCP_Server_Info *server)
|
||||
{
|
||||
|
@ -994,17 +994,17 @@ static int cifs_query_symlink(const unsigned int xid,
|
||||
}
|
||||
|
||||
static int cifs_parse_reparse_point(struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct kvec *rsp_iov,
|
||||
struct cifs_open_info_data *data)
|
||||
{
|
||||
struct reparse_data_buffer *buf;
|
||||
TRANSACT_IOCTL_RSP *io = rsp_iov->iov_base;
|
||||
bool unicode = !!(io->hdr.Flags2 & SMBFLG2_UNICODE);
|
||||
u32 plen = le16_to_cpu(io->ByteCount);
|
||||
|
||||
buf = (struct reparse_data_buffer *)((__u8 *)&io->hdr.Protocol +
|
||||
le32_to_cpu(io->DataOffset));
|
||||
return parse_reparse_point(buf, plen, cifs_sb, unicode, data);
|
||||
return parse_reparse_point(buf, plen, cifs_sb, full_path, true, data);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -63,12 +63,12 @@ static struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov)
|
||||
return sym;
|
||||
}
|
||||
|
||||
int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec *iov, char **path)
|
||||
int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec *iov,
|
||||
const char *full_path, char **path)
|
||||
{
|
||||
struct smb2_symlink_err_rsp *sym;
|
||||
unsigned int sub_offs, sub_len;
|
||||
unsigned int print_offs, print_len;
|
||||
char *s;
|
||||
|
||||
if (!cifs_sb || !iov || !iov->iov_base || !iov->iov_len || !path)
|
||||
return -EINVAL;
|
||||
@ -86,15 +86,13 @@ int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec
|
||||
iov->iov_len < SMB2_SYMLINK_STRUCT_SIZE + print_offs + print_len)
|
||||
return -EINVAL;
|
||||
|
||||
s = cifs_strndup_from_utf16((char *)sym->PathBuffer + sub_offs, sub_len, true,
|
||||
cifs_sb->local_nls);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
convert_delimiter(s, '/');
|
||||
cifs_dbg(FYI, "%s: symlink target: %s\n", __func__, s);
|
||||
|
||||
*path = s;
|
||||
return 0;
|
||||
return smb2_parse_native_symlink(path,
|
||||
(char *)sym->PathBuffer + sub_offs,
|
||||
sub_len,
|
||||
true,
|
||||
le32_to_cpu(sym->Flags) & SYMLINK_FLAG_RELATIVE,
|
||||
full_path,
|
||||
cifs_sb);
|
||||
}
|
||||
|
||||
int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock, void *buf)
|
||||
@ -126,6 +124,7 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32
|
||||
goto out;
|
||||
if (hdr->Status == STATUS_STOPPED_ON_SYMLINK) {
|
||||
rc = smb2_parse_symlink_response(oparms->cifs_sb, &err_iov,
|
||||
oparms->path,
|
||||
&data->symlink_target);
|
||||
if (!rc) {
|
||||
memset(smb2_data, 0, sizeof(*smb2_data));
|
||||
|
@ -828,6 +828,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
||||
static int parse_create_response(struct cifs_open_info_data *data,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
const struct kvec *iov)
|
||||
{
|
||||
struct smb2_create_rsp *rsp = iov->iov_base;
|
||||
@ -841,6 +842,7 @@ static int parse_create_response(struct cifs_open_info_data *data,
|
||||
break;
|
||||
case STATUS_STOPPED_ON_SYMLINK:
|
||||
rc = smb2_parse_symlink_response(cifs_sb, iov,
|
||||
full_path,
|
||||
&data->symlink_target);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -930,14 +932,14 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
|
||||
switch (rc) {
|
||||
case 0:
|
||||
rc = parse_create_response(data, cifs_sb, &out_iov[0]);
|
||||
rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
|
||||
break;
|
||||
case -EOPNOTSUPP:
|
||||
/*
|
||||
* BB TODO: When support for special files added to Samba
|
||||
* re-verify this path.
|
||||
*/
|
||||
rc = parse_create_response(data, cifs_sb, &out_iov[0]);
|
||||
rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
|
||||
if (rc || !data->reparse_point)
|
||||
goto out;
|
||||
|
||||
|
@ -2932,7 +2932,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
||||
struct fsctl_get_dfs_referral_req *dfs_req = NULL;
|
||||
struct get_dfs_referral_rsp *dfs_rsp = NULL;
|
||||
u32 dfs_req_size = 0, dfs_rsp_size = 0;
|
||||
int retry_count = 0;
|
||||
int retry_once = 0;
|
||||
|
||||
cifs_dbg(FYI, "%s: path: %s\n", __func__, search_name);
|
||||
|
||||
@ -2981,21 +2981,25 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
||||
/* Path to resolve in an UTF-16 null-terminated string */
|
||||
memcpy(dfs_req->RequestFileName, utf16_path, utf16_path_len);
|
||||
|
||||
do {
|
||||
for (;;) {
|
||||
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
|
||||
FSCTL_DFS_GET_REFERRALS,
|
||||
(char *)dfs_req, dfs_req_size, CIFSMaxBufSize,
|
||||
(char **)&dfs_rsp, &dfs_rsp_size);
|
||||
if (!is_retryable_error(rc))
|
||||
if (fatal_signal_pending(current)) {
|
||||
rc = -EINTR;
|
||||
break;
|
||||
}
|
||||
if (!is_retryable_error(rc) || retry_once++)
|
||||
break;
|
||||
usleep_range(512, 2048);
|
||||
} while (++retry_count < 5);
|
||||
}
|
||||
|
||||
if (!rc && !dfs_rsp)
|
||||
rc = -EIO;
|
||||
if (rc) {
|
||||
if (!is_retryable_error(rc) && rc != -ENOENT && rc != -EOPNOTSUPP)
|
||||
cifs_tcon_dbg(VFS, "%s: ioctl error: rc=%d\n", __func__, rc);
|
||||
cifs_tcon_dbg(FYI, "%s: ioctl error: rc=%d\n", __func__, rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -216,10 +216,9 @@ static int
|
||||
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||
struct TCP_Server_Info *server, bool from_reconnect)
|
||||
{
|
||||
int rc = 0;
|
||||
struct nls_table *nls_codepage = NULL;
|
||||
struct cifs_ses *ses;
|
||||
int xid;
|
||||
int rc = 0;
|
||||
|
||||
/*
|
||||
* SMB2s NegProt, SessSetup, Logoff do not have tcon yet so
|
||||
@ -229,11 +228,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||
if (tcon == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Need to also skip SMB2_IOCTL because it is used for checking nested dfs links in
|
||||
* cifs_tree_connect().
|
||||
*/
|
||||
if (smb2_command == SMB2_TREE_CONNECT || smb2_command == SMB2_IOCTL)
|
||||
if (smb2_command == SMB2_TREE_CONNECT)
|
||||
return 0;
|
||||
|
||||
spin_lock(&tcon->tc_lock);
|
||||
@ -334,8 +329,6 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||
}
|
||||
spin_unlock(&server->srv_lock);
|
||||
|
||||
nls_codepage = ses->local_nls;
|
||||
|
||||
/*
|
||||
* need to prevent multiple threads trying to simultaneously
|
||||
* reconnect the same SMB session
|
||||
@ -372,7 +365,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||
}
|
||||
}
|
||||
|
||||
rc = cifs_setup_session(0, ses, server, nls_codepage);
|
||||
rc = cifs_setup_session(0, ses, server, ses->local_nls);
|
||||
if ((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED)) {
|
||||
/*
|
||||
* Try alternate password for next reconnect (key rotation
|
||||
@ -406,7 +399,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||
if (tcon->use_persistent)
|
||||
tcon->need_reopen_files = true;
|
||||
|
||||
rc = cifs_tree_connect(0, tcon, nls_codepage);
|
||||
rc = cifs_tree_connect(0, tcon);
|
||||
|
||||
cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
|
||||
if (rc) {
|
||||
@ -494,6 +487,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
|
||||
case SMB2_CHANGE_NOTIFY:
|
||||
case SMB2_QUERY_INFO:
|
||||
case SMB2_SET_INFO:
|
||||
case SMB2_IOCTL:
|
||||
rc = -EAGAIN;
|
||||
}
|
||||
failed:
|
||||
@ -1231,7 +1225,9 @@ SMB2_negotiate(const unsigned int xid,
|
||||
* SMB3.0 supports only 1 cipher and doesn't have a encryption neg context
|
||||
* Set the cipher type manually.
|
||||
*/
|
||||
if (server->dialect == SMB30_PROT_ID && (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
|
||||
if ((server->dialect == SMB30_PROT_ID ||
|
||||
server->dialect == SMB302_PROT_ID) &&
|
||||
(server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
|
||||
server->cipher_type = SMB2_ENCRYPTION_AES128_CCM;
|
||||
|
||||
security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
|
||||
|
@ -111,7 +111,14 @@ extern int smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const unsigned char *path, char *pbuf,
|
||||
unsigned int *pbytes_read);
|
||||
int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec *iov, char **path);
|
||||
int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
|
||||
bool unicode, bool relative,
|
||||
const char *full_path,
|
||||
struct cifs_sb_info *cifs_sb);
|
||||
int smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb,
|
||||
const struct kvec *iov,
|
||||
const char *full_path,
|
||||
char **path);
|
||||
int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
|
||||
void *buf);
|
||||
extern int smb2_unlock_range(struct cifsFileInfo *cfile,
|
||||
|
@ -44,6 +44,8 @@
|
||||
EM(netfs_trace_tcon_ref_free_ipc, "FRE Ipc ") \
|
||||
EM(netfs_trace_tcon_ref_free_ipc_fail, "FRE Ipc-F ") \
|
||||
EM(netfs_trace_tcon_ref_free_reconnect_server, "FRE Reconn") \
|
||||
EM(netfs_trace_tcon_ref_get_cached_laundromat, "GET Ch-Lau") \
|
||||
EM(netfs_trace_tcon_ref_get_cached_lease_break, "GET Ch-Lea") \
|
||||
EM(netfs_trace_tcon_ref_get_cancelled_close, "GET Cn-Cls") \
|
||||
EM(netfs_trace_tcon_ref_get_dfs_refer, "GET DfsRef") \
|
||||
EM(netfs_trace_tcon_ref_get_find, "GET Find ") \
|
||||
@ -52,6 +54,7 @@
|
||||
EM(netfs_trace_tcon_ref_new, "NEW ") \
|
||||
EM(netfs_trace_tcon_ref_new_ipc, "NEW Ipc ") \
|
||||
EM(netfs_trace_tcon_ref_new_reconnect_server, "NEW Reconn") \
|
||||
EM(netfs_trace_tcon_ref_put_cached_close, "PUT Ch-Cls") \
|
||||
EM(netfs_trace_tcon_ref_put_cancelled_close, "PUT Cn-Cls") \
|
||||
EM(netfs_trace_tcon_ref_put_cancelled_close_fid, "PUT Cn-Fid") \
|
||||
EM(netfs_trace_tcon_ref_put_cancelled_mid, "PUT Cn-Mid") \
|
||||
|
@ -1552,6 +1552,15 @@ struct reparse_symlink_data_buffer {
|
||||
|
||||
/* See MS-FSCC 2.1.2.6 and cifspdu.h for struct reparse_posix_data */
|
||||
|
||||
/* For IO_REPARSE_TAG_LX_SYMLINK */
|
||||
struct reparse_wsl_symlink_data_buffer {
|
||||
__le32 ReparseTag;
|
||||
__le16 ReparseDataLength;
|
||||
__u16 Reserved;
|
||||
__le32 Flags;
|
||||
__u8 PathBuffer[]; /* Variable Length UTF-8 string without nul-term */
|
||||
} __packed;
|
||||
|
||||
struct validate_negotiate_info_req {
|
||||
__le32 Capabilities;
|
||||
__u8 Guid[SMB2_CLIENT_GUID_SIZE];
|
||||
|
Loading…
Reference in New Issue
Block a user