xref: /openbmc/linux/fs/smb/client/misc.c (revision c005e2f62f8421b13b9a31adb9db7281f1a19e68)
138c8a9a5SSteve French // SPDX-License-Identifier: LGPL-2.1
238c8a9a5SSteve French /*
338c8a9a5SSteve French  *
438c8a9a5SSteve French  *   Copyright (C) International Business Machines  Corp., 2002,2008
538c8a9a5SSteve French  *   Author(s): Steve French (sfrench@us.ibm.com)
638c8a9a5SSteve French  *
738c8a9a5SSteve French  */
838c8a9a5SSteve French 
938c8a9a5SSteve French #include <linux/slab.h>
1038c8a9a5SSteve French #include <linux/ctype.h>
1138c8a9a5SSteve French #include <linux/mempool.h>
1238c8a9a5SSteve French #include <linux/vmalloc.h>
1338c8a9a5SSteve French #include "cifspdu.h"
1438c8a9a5SSteve French #include "cifsglob.h"
1538c8a9a5SSteve French #include "cifsproto.h"
1638c8a9a5SSteve French #include "cifs_debug.h"
1738c8a9a5SSteve French #include "smberr.h"
1838c8a9a5SSteve French #include "nterr.h"
1938c8a9a5SSteve French #include "cifs_unicode.h"
2038c8a9a5SSteve French #include "smb2pdu.h"
2138c8a9a5SSteve French #include "cifsfs.h"
2238c8a9a5SSteve French #ifdef CONFIG_CIFS_DFS_UPCALL
2338c8a9a5SSteve French #include "dns_resolve.h"
2438c8a9a5SSteve French #include "dfs_cache.h"
2538c8a9a5SSteve French #include "dfs.h"
2638c8a9a5SSteve French #endif
2738c8a9a5SSteve French #include "fs_context.h"
2838c8a9a5SSteve French #include "cached_dir.h"
2938c8a9a5SSteve French 
3038c8a9a5SSteve French /* The xid serves as a useful identifier for each incoming vfs request,
3138c8a9a5SSteve French    in a similar way to the mid which is useful to track each sent smb,
3238c8a9a5SSteve French    and CurrentXid can also provide a running counter (although it
3338c8a9a5SSteve French    will eventually wrap past zero) of the total vfs operations handled
3438c8a9a5SSteve French    since the cifs fs was mounted */
3538c8a9a5SSteve French 
3638c8a9a5SSteve French unsigned int
_get_xid(void)3738c8a9a5SSteve French _get_xid(void)
3838c8a9a5SSteve French {
3938c8a9a5SSteve French 	unsigned int xid;
4038c8a9a5SSteve French 
4138c8a9a5SSteve French 	spin_lock(&GlobalMid_Lock);
4238c8a9a5SSteve French 	GlobalTotalActiveXid++;
4338c8a9a5SSteve French 
4438c8a9a5SSteve French 	/* keep high water mark for number of simultaneous ops in filesystem */
4538c8a9a5SSteve French 	if (GlobalTotalActiveXid > GlobalMaxActiveXid)
4638c8a9a5SSteve French 		GlobalMaxActiveXid = GlobalTotalActiveXid;
4738c8a9a5SSteve French 	if (GlobalTotalActiveXid > 65000)
4838c8a9a5SSteve French 		cifs_dbg(FYI, "warning: more than 65000 requests active\n");
4938c8a9a5SSteve French 	xid = GlobalCurrentXid++;
5038c8a9a5SSteve French 	spin_unlock(&GlobalMid_Lock);
5138c8a9a5SSteve French 	return xid;
5238c8a9a5SSteve French }
5338c8a9a5SSteve French 
5438c8a9a5SSteve French void
_free_xid(unsigned int xid)5538c8a9a5SSteve French _free_xid(unsigned int xid)
5638c8a9a5SSteve French {
5738c8a9a5SSteve French 	spin_lock(&GlobalMid_Lock);
5838c8a9a5SSteve French 	/* if (GlobalTotalActiveXid == 0)
5938c8a9a5SSteve French 		BUG(); */
6038c8a9a5SSteve French 	GlobalTotalActiveXid--;
6138c8a9a5SSteve French 	spin_unlock(&GlobalMid_Lock);
6238c8a9a5SSteve French }
6338c8a9a5SSteve French 
6438c8a9a5SSteve French struct cifs_ses *
sesInfoAlloc(void)6538c8a9a5SSteve French sesInfoAlloc(void)
6638c8a9a5SSteve French {
6738c8a9a5SSteve French 	struct cifs_ses *ret_buf;
6838c8a9a5SSteve French 
6938c8a9a5SSteve French 	ret_buf = kzalloc(sizeof(struct cifs_ses), GFP_KERNEL);
7038c8a9a5SSteve French 	if (ret_buf) {
7138c8a9a5SSteve French 		atomic_inc(&sesInfoAllocCount);
7238c8a9a5SSteve French 		spin_lock_init(&ret_buf->ses_lock);
7338c8a9a5SSteve French 		ret_buf->ses_status = SES_NEW;
7438c8a9a5SSteve French 		++ret_buf->ses_count;
7538c8a9a5SSteve French 		INIT_LIST_HEAD(&ret_buf->smb_ses_list);
7638c8a9a5SSteve French 		INIT_LIST_HEAD(&ret_buf->tcon_list);
7738c8a9a5SSteve French 		mutex_init(&ret_buf->session_mutex);
7838c8a9a5SSteve French 		spin_lock_init(&ret_buf->iface_lock);
7938c8a9a5SSteve French 		INIT_LIST_HEAD(&ret_buf->iface_list);
8038c8a9a5SSteve French 		spin_lock_init(&ret_buf->chan_lock);
8138c8a9a5SSteve French 	}
8238c8a9a5SSteve French 	return ret_buf;
8338c8a9a5SSteve French }
8438c8a9a5SSteve French 
8538c8a9a5SSteve French void
sesInfoFree(struct cifs_ses * buf_to_free)8638c8a9a5SSteve French sesInfoFree(struct cifs_ses *buf_to_free)
8738c8a9a5SSteve French {
8838c8a9a5SSteve French 	struct cifs_server_iface *iface = NULL, *niface = NULL;
8938c8a9a5SSteve French 
9038c8a9a5SSteve French 	if (buf_to_free == NULL) {
9138c8a9a5SSteve French 		cifs_dbg(FYI, "Null buffer passed to sesInfoFree\n");
9238c8a9a5SSteve French 		return;
9338c8a9a5SSteve French 	}
9438c8a9a5SSteve French 
95a43f95fdSWinston Wen 	unload_nls(buf_to_free->local_nls);
9638c8a9a5SSteve French 	atomic_dec(&sesInfoAllocCount);
9738c8a9a5SSteve French 	kfree(buf_to_free->serverOS);
9838c8a9a5SSteve French 	kfree(buf_to_free->serverDomain);
9938c8a9a5SSteve French 	kfree(buf_to_free->serverNOS);
10038c8a9a5SSteve French 	kfree_sensitive(buf_to_free->password);
10108bedfbcSSteve French 	kfree_sensitive(buf_to_free->password2);
10238c8a9a5SSteve French 	kfree(buf_to_free->user_name);
10338c8a9a5SSteve French 	kfree(buf_to_free->domainName);
10438c8a9a5SSteve French 	kfree_sensitive(buf_to_free->auth_key.response);
10538c8a9a5SSteve French 	spin_lock(&buf_to_free->iface_lock);
10638c8a9a5SSteve French 	list_for_each_entry_safe(iface, niface, &buf_to_free->iface_list,
10738c8a9a5SSteve French 				 iface_head)
10838c8a9a5SSteve French 		kref_put(&iface->refcount, release_iface);
10938c8a9a5SSteve French 	spin_unlock(&buf_to_free->iface_lock);
11038c8a9a5SSteve French 	kfree_sensitive(buf_to_free);
11138c8a9a5SSteve French }
11238c8a9a5SSteve French 
11338c8a9a5SSteve French struct cifs_tcon *
tcon_info_alloc(bool dir_leases_enabled,enum smb3_tcon_ref_trace trace)11407e76ea1SDavid Howells tcon_info_alloc(bool dir_leases_enabled, enum smb3_tcon_ref_trace trace)
11538c8a9a5SSteve French {
11638c8a9a5SSteve French 	struct cifs_tcon *ret_buf;
11707e76ea1SDavid Howells 	static atomic_t tcon_debug_id;
11838c8a9a5SSteve French 
11938c8a9a5SSteve French 	ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL);
12038c8a9a5SSteve French 	if (!ret_buf)
12138c8a9a5SSteve French 		return NULL;
1222da338ffSSteve French 
1232da338ffSSteve French 	if (dir_leases_enabled == true) {
12438c8a9a5SSteve French 		ret_buf->cfids = init_cached_dirs();
12538c8a9a5SSteve French 		if (!ret_buf->cfids) {
12638c8a9a5SSteve French 			kfree(ret_buf);
12738c8a9a5SSteve French 			return NULL;
12838c8a9a5SSteve French 		}
1292da338ffSSteve French 	}
1302da338ffSSteve French 	/* else ret_buf->cfids is already set to NULL above */
13138c8a9a5SSteve French 
13238c8a9a5SSteve French 	atomic_inc(&tconInfoAllocCount);
13338c8a9a5SSteve French 	ret_buf->status = TID_NEW;
13407e76ea1SDavid Howells 	ret_buf->debug_id = atomic_inc_return(&tcon_debug_id);
13507e76ea1SDavid Howells 	ret_buf->tc_count = 1;
13638c8a9a5SSteve French 	spin_lock_init(&ret_buf->tc_lock);
13738c8a9a5SSteve French 	INIT_LIST_HEAD(&ret_buf->openFileList);
13838c8a9a5SSteve French 	INIT_LIST_HEAD(&ret_buf->tcon_list);
13938c8a9a5SSteve French 	spin_lock_init(&ret_buf->open_file_lock);
14038c8a9a5SSteve French 	spin_lock_init(&ret_buf->stat_lock);
14138c8a9a5SSteve French 	atomic_set(&ret_buf->num_local_opens, 0);
14238c8a9a5SSteve French 	atomic_set(&ret_buf->num_remote_opens, 0);
143441786beSSteve French 	ret_buf->stats_from_time = ktime_get_real_seconds();
1444a5c16d0SDavid Howells #ifdef CONFIG_CIFS_FSCACHE
1454a5c16d0SDavid Howells 	mutex_init(&ret_buf->fscache_lock);
1464a5c16d0SDavid Howells #endif
14707e76ea1SDavid Howells 	trace_smb3_tcon_ref(ret_buf->debug_id, ret_buf->tc_count, trace);
14838c8a9a5SSteve French 
14938c8a9a5SSteve French 	return ret_buf;
15038c8a9a5SSteve French }
15138c8a9a5SSteve French 
15238c8a9a5SSteve French void
tconInfoFree(struct cifs_tcon * tcon,enum smb3_tcon_ref_trace trace)15307e76ea1SDavid Howells tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace)
15438c8a9a5SSteve French {
15538c8a9a5SSteve French 	if (tcon == NULL) {
15638c8a9a5SSteve French 		cifs_dbg(FYI, "Null buffer passed to tconInfoFree\n");
15738c8a9a5SSteve French 		return;
15838c8a9a5SSteve French 	}
15907e76ea1SDavid Howells 	trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, trace);
16038c8a9a5SSteve French 	free_cached_dirs(tcon->cfids);
16138c8a9a5SSteve French 	atomic_dec(&tconInfoAllocCount);
16238c8a9a5SSteve French 	kfree(tcon->nativeFileSystem);
16338c8a9a5SSteve French 	kfree_sensitive(tcon->password);
1643ae872deSPaulo Alcantara 	kfree(tcon->origin_fullpath);
16538c8a9a5SSteve French 	kfree(tcon);
16638c8a9a5SSteve French }
16738c8a9a5SSteve French 
16838c8a9a5SSteve French struct smb_hdr *
cifs_buf_get(void)16938c8a9a5SSteve French cifs_buf_get(void)
17038c8a9a5SSteve French {
17138c8a9a5SSteve French 	struct smb_hdr *ret_buf = NULL;
17238c8a9a5SSteve French 	/*
17338c8a9a5SSteve French 	 * SMB2 header is bigger than CIFS one - no problems to clean some
17438c8a9a5SSteve French 	 * more bytes for CIFS.
17538c8a9a5SSteve French 	 */
17638c8a9a5SSteve French 	size_t buf_size = sizeof(struct smb2_hdr);
17738c8a9a5SSteve French 
17838c8a9a5SSteve French 	/*
17938c8a9a5SSteve French 	 * We could use negotiated size instead of max_msgsize -
18038c8a9a5SSteve French 	 * but it may be more efficient to always alloc same size
18138c8a9a5SSteve French 	 * albeit slightly larger than necessary and maxbuffersize
18238c8a9a5SSteve French 	 * defaults to this and can not be bigger.
18338c8a9a5SSteve French 	 */
18438c8a9a5SSteve French 	ret_buf = mempool_alloc(cifs_req_poolp, GFP_NOFS);
18538c8a9a5SSteve French 
18638c8a9a5SSteve French 	/* clear the first few header bytes */
18738c8a9a5SSteve French 	/* for most paths, more is cleared in header_assemble */
18838c8a9a5SSteve French 	memset(ret_buf, 0, buf_size + 3);
18938c8a9a5SSteve French 	atomic_inc(&buf_alloc_count);
19038c8a9a5SSteve French #ifdef CONFIG_CIFS_STATS2
19138c8a9a5SSteve French 	atomic_inc(&total_buf_alloc_count);
19238c8a9a5SSteve French #endif /* CONFIG_CIFS_STATS2 */
19338c8a9a5SSteve French 
19438c8a9a5SSteve French 	return ret_buf;
19538c8a9a5SSteve French }
19638c8a9a5SSteve French 
19738c8a9a5SSteve French void
cifs_buf_release(void * buf_to_free)19838c8a9a5SSteve French cifs_buf_release(void *buf_to_free)
19938c8a9a5SSteve French {
20038c8a9a5SSteve French 	if (buf_to_free == NULL) {
20138c8a9a5SSteve French 		/* cifs_dbg(FYI, "Null buffer passed to cifs_buf_release\n");*/
20238c8a9a5SSteve French 		return;
20338c8a9a5SSteve French 	}
20438c8a9a5SSteve French 	mempool_free(buf_to_free, cifs_req_poolp);
20538c8a9a5SSteve French 
20638c8a9a5SSteve French 	atomic_dec(&buf_alloc_count);
20738c8a9a5SSteve French 	return;
20838c8a9a5SSteve French }
20938c8a9a5SSteve French 
21038c8a9a5SSteve French struct smb_hdr *
cifs_small_buf_get(void)21138c8a9a5SSteve French cifs_small_buf_get(void)
21238c8a9a5SSteve French {
21338c8a9a5SSteve French 	struct smb_hdr *ret_buf = NULL;
21438c8a9a5SSteve French 
21538c8a9a5SSteve French /* We could use negotiated size instead of max_msgsize -
21638c8a9a5SSteve French    but it may be more efficient to always alloc same size
21738c8a9a5SSteve French    albeit slightly larger than necessary and maxbuffersize
21838c8a9a5SSteve French    defaults to this and can not be bigger */
21938c8a9a5SSteve French 	ret_buf = mempool_alloc(cifs_sm_req_poolp, GFP_NOFS);
22038c8a9a5SSteve French 	/* No need to clear memory here, cleared in header assemble */
22138c8a9a5SSteve French 	/*	memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
22238c8a9a5SSteve French 	atomic_inc(&small_buf_alloc_count);
22338c8a9a5SSteve French #ifdef CONFIG_CIFS_STATS2
22438c8a9a5SSteve French 	atomic_inc(&total_small_buf_alloc_count);
22538c8a9a5SSteve French #endif /* CONFIG_CIFS_STATS2 */
22638c8a9a5SSteve French 
22738c8a9a5SSteve French 	return ret_buf;
22838c8a9a5SSteve French }
22938c8a9a5SSteve French 
23038c8a9a5SSteve French void
cifs_small_buf_release(void * buf_to_free)23138c8a9a5SSteve French cifs_small_buf_release(void *buf_to_free)
23238c8a9a5SSteve French {
23338c8a9a5SSteve French 
23438c8a9a5SSteve French 	if (buf_to_free == NULL) {
23538c8a9a5SSteve French 		cifs_dbg(FYI, "Null buffer passed to cifs_small_buf_release\n");
23638c8a9a5SSteve French 		return;
23738c8a9a5SSteve French 	}
23838c8a9a5SSteve French 	mempool_free(buf_to_free, cifs_sm_req_poolp);
23938c8a9a5SSteve French 
24038c8a9a5SSteve French 	atomic_dec(&small_buf_alloc_count);
24138c8a9a5SSteve French 	return;
24238c8a9a5SSteve French }
24338c8a9a5SSteve French 
24438c8a9a5SSteve French void
free_rsp_buf(int resp_buftype,void * rsp)24538c8a9a5SSteve French free_rsp_buf(int resp_buftype, void *rsp)
24638c8a9a5SSteve French {
24738c8a9a5SSteve French 	if (resp_buftype == CIFS_SMALL_BUFFER)
24838c8a9a5SSteve French 		cifs_small_buf_release(rsp);
24938c8a9a5SSteve French 	else if (resp_buftype == CIFS_LARGE_BUFFER)
25038c8a9a5SSteve French 		cifs_buf_release(rsp);
25138c8a9a5SSteve French }
25238c8a9a5SSteve French 
25338c8a9a5SSteve French /* NB: MID can not be set if treeCon not passed in, in that
25438c8a9a5SSteve French    case it is responsbility of caller to set the mid */
25538c8a9a5SSteve French void
header_assemble(struct smb_hdr * buffer,char smb_command,const struct cifs_tcon * treeCon,int word_count)25638c8a9a5SSteve French header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
25738c8a9a5SSteve French 		const struct cifs_tcon *treeCon, int word_count
25838c8a9a5SSteve French 		/* length of fixed section (word count) in two byte units  */)
25938c8a9a5SSteve French {
26038c8a9a5SSteve French 	char *temp = (char *) buffer;
26138c8a9a5SSteve French 
26238c8a9a5SSteve French 	memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
26338c8a9a5SSteve French 
26438c8a9a5SSteve French 	buffer->smb_buf_length = cpu_to_be32(
26538c8a9a5SSteve French 	    (2 * word_count) + sizeof(struct smb_hdr) -
26638c8a9a5SSteve French 	    4 /*  RFC 1001 length field does not count */  +
26738c8a9a5SSteve French 	    2 /* for bcc field itself */) ;
26838c8a9a5SSteve French 
26938c8a9a5SSteve French 	buffer->Protocol[0] = 0xFF;
27038c8a9a5SSteve French 	buffer->Protocol[1] = 'S';
27138c8a9a5SSteve French 	buffer->Protocol[2] = 'M';
27238c8a9a5SSteve French 	buffer->Protocol[3] = 'B';
27338c8a9a5SSteve French 	buffer->Command = smb_command;
27438c8a9a5SSteve French 	buffer->Flags = 0x00;	/* case sensitive */
27538c8a9a5SSteve French 	buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
27638c8a9a5SSteve French 	buffer->Pid = cpu_to_le16((__u16)current->tgid);
27738c8a9a5SSteve French 	buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
27838c8a9a5SSteve French 	if (treeCon) {
27938c8a9a5SSteve French 		buffer->Tid = treeCon->tid;
28038c8a9a5SSteve French 		if (treeCon->ses) {
28138c8a9a5SSteve French 			if (treeCon->ses->capabilities & CAP_UNICODE)
28238c8a9a5SSteve French 				buffer->Flags2 |= SMBFLG2_UNICODE;
28338c8a9a5SSteve French 			if (treeCon->ses->capabilities & CAP_STATUS32)
28438c8a9a5SSteve French 				buffer->Flags2 |= SMBFLG2_ERR_STATUS;
28538c8a9a5SSteve French 
28638c8a9a5SSteve French 			/* Uid is not converted */
28738c8a9a5SSteve French 			buffer->Uid = treeCon->ses->Suid;
28838c8a9a5SSteve French 			if (treeCon->ses->server)
28938c8a9a5SSteve French 				buffer->Mid = get_next_mid(treeCon->ses->server);
29038c8a9a5SSteve French 		}
29138c8a9a5SSteve French 		if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
29238c8a9a5SSteve French 			buffer->Flags2 |= SMBFLG2_DFS;
29338c8a9a5SSteve French 		if (treeCon->nocase)
29438c8a9a5SSteve French 			buffer->Flags  |= SMBFLG_CASELESS;
29538c8a9a5SSteve French 		if ((treeCon->ses) && (treeCon->ses->server))
29638c8a9a5SSteve French 			if (treeCon->ses->server->sign)
29738c8a9a5SSteve French 				buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
29838c8a9a5SSteve French 	}
29938c8a9a5SSteve French 
30038c8a9a5SSteve French /*  endian conversion of flags is now done just before sending */
30138c8a9a5SSteve French 	buffer->WordCount = (char) word_count;
30238c8a9a5SSteve French 	return;
30338c8a9a5SSteve French }
30438c8a9a5SSteve French 
30538c8a9a5SSteve French static int
check_smb_hdr(struct smb_hdr * smb)30638c8a9a5SSteve French check_smb_hdr(struct smb_hdr *smb)
30738c8a9a5SSteve French {
30838c8a9a5SSteve French 	/* does it have the right SMB "signature" ? */
30938c8a9a5SSteve French 	if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) {
31038c8a9a5SSteve French 		cifs_dbg(VFS, "Bad protocol string signature header 0x%x\n",
31138c8a9a5SSteve French 			 *(unsigned int *)smb->Protocol);
31238c8a9a5SSteve French 		return 1;
31338c8a9a5SSteve French 	}
31438c8a9a5SSteve French 
31538c8a9a5SSteve French 	/* if it's a response then accept */
31638c8a9a5SSteve French 	if (smb->Flags & SMBFLG_RESPONSE)
31738c8a9a5SSteve French 		return 0;
31838c8a9a5SSteve French 
31938c8a9a5SSteve French 	/* only one valid case where server sends us request */
32038c8a9a5SSteve French 	if (smb->Command == SMB_COM_LOCKING_ANDX)
32138c8a9a5SSteve French 		return 0;
32238c8a9a5SSteve French 
32338c8a9a5SSteve French 	cifs_dbg(VFS, "Server sent request, not response. mid=%u\n",
32438c8a9a5SSteve French 		 get_mid(smb));
32538c8a9a5SSteve French 	return 1;
32638c8a9a5SSteve French }
32738c8a9a5SSteve French 
32838c8a9a5SSteve French int
checkSMB(char * buf,unsigned int total_read,struct TCP_Server_Info * server)32938c8a9a5SSteve French checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server)
33038c8a9a5SSteve French {
33138c8a9a5SSteve French 	struct smb_hdr *smb = (struct smb_hdr *)buf;
33238c8a9a5SSteve French 	__u32 rfclen = be32_to_cpu(smb->smb_buf_length);
33338c8a9a5SSteve French 	__u32 clc_len;  /* calculated length */
33438c8a9a5SSteve French 	cifs_dbg(FYI, "checkSMB Length: 0x%x, smb_buf_length: 0x%x\n",
33538c8a9a5SSteve French 		 total_read, rfclen);
33638c8a9a5SSteve French 
33738c8a9a5SSteve French 	/* is this frame too small to even get to a BCC? */
33838c8a9a5SSteve French 	if (total_read < 2 + sizeof(struct smb_hdr)) {
33938c8a9a5SSteve French 		if ((total_read >= sizeof(struct smb_hdr) - 1)
34038c8a9a5SSteve French 			    && (smb->Status.CifsError != 0)) {
34138c8a9a5SSteve French 			/* it's an error return */
34238c8a9a5SSteve French 			smb->WordCount = 0;
34338c8a9a5SSteve French 			/* some error cases do not return wct and bcc */
34438c8a9a5SSteve French 			return 0;
34538c8a9a5SSteve French 		} else if ((total_read == sizeof(struct smb_hdr) + 1) &&
34638c8a9a5SSteve French 				(smb->WordCount == 0)) {
34738c8a9a5SSteve French 			char *tmp = (char *)smb;
34838c8a9a5SSteve French 			/* Need to work around a bug in two servers here */
34938c8a9a5SSteve French 			/* First, check if the part of bcc they sent was zero */
35038c8a9a5SSteve French 			if (tmp[sizeof(struct smb_hdr)] == 0) {
35138c8a9a5SSteve French 				/* some servers return only half of bcc
35238c8a9a5SSteve French 				 * on simple responses (wct, bcc both zero)
35338c8a9a5SSteve French 				 * in particular have seen this on
35438c8a9a5SSteve French 				 * ulogoffX and FindClose. This leaves
35538c8a9a5SSteve French 				 * one byte of bcc potentially unitialized
35638c8a9a5SSteve French 				 */
35738c8a9a5SSteve French 				/* zero rest of bcc */
35838c8a9a5SSteve French 				tmp[sizeof(struct smb_hdr)+1] = 0;
35938c8a9a5SSteve French 				return 0;
36038c8a9a5SSteve French 			}
36138c8a9a5SSteve French 			cifs_dbg(VFS, "rcvd invalid byte count (bcc)\n");
36238c8a9a5SSteve French 		} else {
36338c8a9a5SSteve French 			cifs_dbg(VFS, "Length less than smb header size\n");
36438c8a9a5SSteve French 		}
36538c8a9a5SSteve French 		return -EIO;
366ac48fcefSPaulo Alcantara 	} else if (total_read < sizeof(*smb) + 2 * smb->WordCount) {
367ac48fcefSPaulo Alcantara 		cifs_dbg(VFS, "%s: can't read BCC due to invalid WordCount(%u)\n",
368ac48fcefSPaulo Alcantara 			 __func__, smb->WordCount);
369ac48fcefSPaulo Alcantara 		return -EIO;
37038c8a9a5SSteve French 	}
37138c8a9a5SSteve French 
37238c8a9a5SSteve French 	/* otherwise, there is enough to get to the BCC */
37338c8a9a5SSteve French 	if (check_smb_hdr(smb))
37438c8a9a5SSteve French 		return -EIO;
37538c8a9a5SSteve French 	clc_len = smbCalcSize(smb);
37638c8a9a5SSteve French 
37738c8a9a5SSteve French 	if (4 + rfclen != total_read) {
37838c8a9a5SSteve French 		cifs_dbg(VFS, "Length read does not match RFC1001 length %d\n",
37938c8a9a5SSteve French 			 rfclen);
38038c8a9a5SSteve French 		return -EIO;
38138c8a9a5SSteve French 	}
38238c8a9a5SSteve French 
38338c8a9a5SSteve French 	if (4 + rfclen != clc_len) {
38438c8a9a5SSteve French 		__u16 mid = get_mid(smb);
38538c8a9a5SSteve French 		/* check if bcc wrapped around for large read responses */
38638c8a9a5SSteve French 		if ((rfclen > 64 * 1024) && (rfclen > clc_len)) {
38738c8a9a5SSteve French 			/* check if lengths match mod 64K */
38838c8a9a5SSteve French 			if (((4 + rfclen) & 0xFFFF) == (clc_len & 0xFFFF))
38938c8a9a5SSteve French 				return 0; /* bcc wrapped */
39038c8a9a5SSteve French 		}
39138c8a9a5SSteve French 		cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u\n",
39238c8a9a5SSteve French 			 clc_len, 4 + rfclen, mid);
39338c8a9a5SSteve French 
39438c8a9a5SSteve French 		if (4 + rfclen < clc_len) {
39538c8a9a5SSteve French 			cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n",
39638c8a9a5SSteve French 				 rfclen, mid);
39738c8a9a5SSteve French 			return -EIO;
39838c8a9a5SSteve French 		} else if (rfclen > clc_len + 512) {
39938c8a9a5SSteve French 			/*
40038c8a9a5SSteve French 			 * Some servers (Windows XP in particular) send more
40138c8a9a5SSteve French 			 * data than the lengths in the SMB packet would
40238c8a9a5SSteve French 			 * indicate on certain calls (byte range locks and
40338c8a9a5SSteve French 			 * trans2 find first calls in particular). While the
40438c8a9a5SSteve French 			 * client can handle such a frame by ignoring the
40538c8a9a5SSteve French 			 * trailing data, we choose limit the amount of extra
40638c8a9a5SSteve French 			 * data to 512 bytes.
40738c8a9a5SSteve French 			 */
40838c8a9a5SSteve French 			cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n",
40938c8a9a5SSteve French 				 rfclen, mid);
41038c8a9a5SSteve French 			return -EIO;
41138c8a9a5SSteve French 		}
41238c8a9a5SSteve French 	}
41338c8a9a5SSteve French 	return 0;
41438c8a9a5SSteve French }
41538c8a9a5SSteve French 
41638c8a9a5SSteve French bool
is_valid_oplock_break(char * buffer,struct TCP_Server_Info * srv)41738c8a9a5SSteve French is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
41838c8a9a5SSteve French {
41938c8a9a5SSteve French 	struct smb_hdr *buf = (struct smb_hdr *)buffer;
42038c8a9a5SSteve French 	struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
42138c8a9a5SSteve French 	struct TCP_Server_Info *pserver;
42238c8a9a5SSteve French 	struct cifs_ses *ses;
42338c8a9a5SSteve French 	struct cifs_tcon *tcon;
42438c8a9a5SSteve French 	struct cifsInodeInfo *pCifsInode;
42538c8a9a5SSteve French 	struct cifsFileInfo *netfile;
42638c8a9a5SSteve French 
42738c8a9a5SSteve French 	cifs_dbg(FYI, "Checking for oplock break or dnotify response\n");
42838c8a9a5SSteve French 	if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
42938c8a9a5SSteve French 	   (pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
43038c8a9a5SSteve French 		struct smb_com_transaction_change_notify_rsp *pSMBr =
43138c8a9a5SSteve French 			(struct smb_com_transaction_change_notify_rsp *)buf;
43238c8a9a5SSteve French 		struct file_notify_information *pnotify;
43338c8a9a5SSteve French 		__u32 data_offset = 0;
43438c8a9a5SSteve French 		size_t len = srv->total_read - sizeof(pSMBr->hdr.smb_buf_length);
43538c8a9a5SSteve French 
43638c8a9a5SSteve French 		if (get_bcc(buf) > sizeof(struct file_notify_information)) {
43738c8a9a5SSteve French 			data_offset = le32_to_cpu(pSMBr->DataOffset);
43838c8a9a5SSteve French 
43938c8a9a5SSteve French 			if (data_offset >
44038c8a9a5SSteve French 			    len - sizeof(struct file_notify_information)) {
44138c8a9a5SSteve French 				cifs_dbg(FYI, "Invalid data_offset %u\n",
44238c8a9a5SSteve French 					 data_offset);
44338c8a9a5SSteve French 				return true;
44438c8a9a5SSteve French 			}
44538c8a9a5SSteve French 			pnotify = (struct file_notify_information *)
44638c8a9a5SSteve French 				((char *)&pSMBr->hdr.Protocol + data_offset);
44738c8a9a5SSteve French 			cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n",
44838c8a9a5SSteve French 				 pnotify->FileName, pnotify->Action);
44938c8a9a5SSteve French 			/*   cifs_dump_mem("Rcvd notify Data: ",buf,
45038c8a9a5SSteve French 				sizeof(struct smb_hdr)+60); */
45138c8a9a5SSteve French 			return true;
45238c8a9a5SSteve French 		}
45338c8a9a5SSteve French 		if (pSMBr->hdr.Status.CifsError) {
45438c8a9a5SSteve French 			cifs_dbg(FYI, "notify err 0x%x\n",
45538c8a9a5SSteve French 				 pSMBr->hdr.Status.CifsError);
45638c8a9a5SSteve French 			return true;
45738c8a9a5SSteve French 		}
45838c8a9a5SSteve French 		return false;
45938c8a9a5SSteve French 	}
46038c8a9a5SSteve French 	if (pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
46138c8a9a5SSteve French 		return false;
46238c8a9a5SSteve French 	if (pSMB->hdr.Flags & SMBFLG_RESPONSE) {
46338c8a9a5SSteve French 		/* no sense logging error on invalid handle on oplock
46438c8a9a5SSteve French 		   break - harmless race between close request and oplock
46538c8a9a5SSteve French 		   break response is expected from time to time writing out
46638c8a9a5SSteve French 		   large dirty files cached on the client */
46738c8a9a5SSteve French 		if ((NT_STATUS_INVALID_HANDLE) ==
46838c8a9a5SSteve French 		   le32_to_cpu(pSMB->hdr.Status.CifsError)) {
46938c8a9a5SSteve French 			cifs_dbg(FYI, "Invalid handle on oplock break\n");
47038c8a9a5SSteve French 			return true;
47138c8a9a5SSteve French 		} else if (ERRbadfid ==
47238c8a9a5SSteve French 		   le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
47338c8a9a5SSteve French 			return true;
47438c8a9a5SSteve French 		} else {
47538c8a9a5SSteve French 			return false; /* on valid oplock brk we get "request" */
47638c8a9a5SSteve French 		}
47738c8a9a5SSteve French 	}
47838c8a9a5SSteve French 	if (pSMB->hdr.WordCount != 8)
47938c8a9a5SSteve French 		return false;
48038c8a9a5SSteve French 
48138c8a9a5SSteve French 	cifs_dbg(FYI, "oplock type 0x%x level 0x%x\n",
48238c8a9a5SSteve French 		 pSMB->LockType, pSMB->OplockLevel);
48338c8a9a5SSteve French 	if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
48438c8a9a5SSteve French 		return false;
48538c8a9a5SSteve French 
48638c8a9a5SSteve French 	/* If server is a channel, select the primary channel */
487b3773b19SSteve French 	pserver = SERVER_IS_CHAN(srv) ? srv->primary_server : srv;
48838c8a9a5SSteve French 
48938c8a9a5SSteve French 	/* look up tcon based on tid & uid */
49038c8a9a5SSteve French 	spin_lock(&cifs_tcp_ses_lock);
49138c8a9a5SSteve French 	list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) {
4920a15ba88SPaulo Alcantara 		if (cifs_ses_exiting(ses))
4930a15ba88SPaulo Alcantara 			continue;
49438c8a9a5SSteve French 		list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
49538c8a9a5SSteve French 			if (tcon->tid != buf->Tid)
49638c8a9a5SSteve French 				continue;
49738c8a9a5SSteve French 
49838c8a9a5SSteve French 			cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
49938c8a9a5SSteve French 			spin_lock(&tcon->open_file_lock);
50038c8a9a5SSteve French 			list_for_each_entry(netfile, &tcon->openFileList, tlist) {
50138c8a9a5SSteve French 				if (pSMB->Fid != netfile->fid.netfid)
50238c8a9a5SSteve French 					continue;
50338c8a9a5SSteve French 
50438c8a9a5SSteve French 				cifs_dbg(FYI, "file id match, oplock break\n");
50538c8a9a5SSteve French 				pCifsInode = CIFS_I(d_inode(netfile->dentry));
50638c8a9a5SSteve French 
50738c8a9a5SSteve French 				set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK,
50838c8a9a5SSteve French 					&pCifsInode->flags);
50938c8a9a5SSteve French 
51038c8a9a5SSteve French 				netfile->oplock_epoch = 0;
51138c8a9a5SSteve French 				netfile->oplock_level = pSMB->OplockLevel;
51238c8a9a5SSteve French 				netfile->oplock_break_cancelled = false;
51338c8a9a5SSteve French 				cifs_queue_oplock_break(netfile);
51438c8a9a5SSteve French 
51538c8a9a5SSteve French 				spin_unlock(&tcon->open_file_lock);
51638c8a9a5SSteve French 				spin_unlock(&cifs_tcp_ses_lock);
51738c8a9a5SSteve French 				return true;
51838c8a9a5SSteve French 			}
51938c8a9a5SSteve French 			spin_unlock(&tcon->open_file_lock);
52038c8a9a5SSteve French 			spin_unlock(&cifs_tcp_ses_lock);
52138c8a9a5SSteve French 			cifs_dbg(FYI, "No matching file for oplock break\n");
52238c8a9a5SSteve French 			return true;
52338c8a9a5SSteve French 		}
52438c8a9a5SSteve French 	}
52538c8a9a5SSteve French 	spin_unlock(&cifs_tcp_ses_lock);
52638c8a9a5SSteve French 	cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n");
52738c8a9a5SSteve French 	return true;
52838c8a9a5SSteve French }
52938c8a9a5SSteve French 
53038c8a9a5SSteve French void
dump_smb(void * buf,int smb_buf_length)53138c8a9a5SSteve French dump_smb(void *buf, int smb_buf_length)
53238c8a9a5SSteve French {
53338c8a9a5SSteve French 	if (traceSMB == 0)
53438c8a9a5SSteve French 		return;
53538c8a9a5SSteve French 
53638c8a9a5SSteve French 	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, 8, 2, buf,
53738c8a9a5SSteve French 		       smb_buf_length, true);
53838c8a9a5SSteve French }
53938c8a9a5SSteve French 
54038c8a9a5SSteve French void
cifs_autodisable_serverino(struct cifs_sb_info * cifs_sb)54138c8a9a5SSteve French cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
54238c8a9a5SSteve French {
54338c8a9a5SSteve French 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
54438c8a9a5SSteve French 		struct cifs_tcon *tcon = NULL;
54538c8a9a5SSteve French 
54638c8a9a5SSteve French 		if (cifs_sb->master_tlink)
54738c8a9a5SSteve French 			tcon = cifs_sb_master_tcon(cifs_sb);
54838c8a9a5SSteve French 
54938c8a9a5SSteve French 		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
55038c8a9a5SSteve French 		cifs_sb->mnt_cifs_serverino_autodisabled = true;
55138c8a9a5SSteve French 		cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s\n",
55238c8a9a5SSteve French 			 tcon ? tcon->tree_name : "new server");
55338c8a9a5SSteve French 		cifs_dbg(VFS, "The server doesn't seem to support them properly or the files might be on different servers (DFS)\n");
55438c8a9a5SSteve French 		cifs_dbg(VFS, "Hardlinks will not be recognized on this mount. Consider mounting with the \"noserverino\" option to silence this message.\n");
55538c8a9a5SSteve French 
55638c8a9a5SSteve French 	}
55738c8a9a5SSteve French }
55838c8a9a5SSteve French 
cifs_set_oplock_level(struct cifsInodeInfo * cinode,__u32 oplock)55938c8a9a5SSteve French void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
56038c8a9a5SSteve French {
56138c8a9a5SSteve French 	oplock &= 0xF;
56238c8a9a5SSteve French 
56338c8a9a5SSteve French 	if (oplock == OPLOCK_EXCLUSIVE) {
56438c8a9a5SSteve French 		cinode->oplock = CIFS_CACHE_WRITE_FLG | CIFS_CACHE_READ_FLG;
56538c8a9a5SSteve French 		cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
56638c8a9a5SSteve French 			 &cinode->netfs.inode);
56738c8a9a5SSteve French 	} else if (oplock == OPLOCK_READ) {
56838c8a9a5SSteve French 		cinode->oplock = CIFS_CACHE_READ_FLG;
56938c8a9a5SSteve French 		cifs_dbg(FYI, "Level II Oplock granted on inode %p\n",
57038c8a9a5SSteve French 			 &cinode->netfs.inode);
57138c8a9a5SSteve French 	} else
57238c8a9a5SSteve French 		cinode->oplock = 0;
57338c8a9a5SSteve French }
57438c8a9a5SSteve French 
57538c8a9a5SSteve French /*
57638c8a9a5SSteve French  * We wait for oplock breaks to be processed before we attempt to perform
57738c8a9a5SSteve French  * writes.
57838c8a9a5SSteve French  */
cifs_get_writer(struct cifsInodeInfo * cinode)57938c8a9a5SSteve French int cifs_get_writer(struct cifsInodeInfo *cinode)
58038c8a9a5SSteve French {
58138c8a9a5SSteve French 	int rc;
58238c8a9a5SSteve French 
58338c8a9a5SSteve French start:
58438c8a9a5SSteve French 	rc = wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK,
58538c8a9a5SSteve French 			 TASK_KILLABLE);
58638c8a9a5SSteve French 	if (rc)
58738c8a9a5SSteve French 		return rc;
58838c8a9a5SSteve French 
58938c8a9a5SSteve French 	spin_lock(&cinode->writers_lock);
59038c8a9a5SSteve French 	if (!cinode->writers)
59138c8a9a5SSteve French 		set_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
59238c8a9a5SSteve French 	cinode->writers++;
59338c8a9a5SSteve French 	/* Check to see if we have started servicing an oplock break */
59438c8a9a5SSteve French 	if (test_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags)) {
59538c8a9a5SSteve French 		cinode->writers--;
59638c8a9a5SSteve French 		if (cinode->writers == 0) {
59738c8a9a5SSteve French 			clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
59838c8a9a5SSteve French 			wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS);
59938c8a9a5SSteve French 		}
60038c8a9a5SSteve French 		spin_unlock(&cinode->writers_lock);
60138c8a9a5SSteve French 		goto start;
60238c8a9a5SSteve French 	}
60338c8a9a5SSteve French 	spin_unlock(&cinode->writers_lock);
60438c8a9a5SSteve French 	return 0;
60538c8a9a5SSteve French }
60638c8a9a5SSteve French 
cifs_put_writer(struct cifsInodeInfo * cinode)60738c8a9a5SSteve French void cifs_put_writer(struct cifsInodeInfo *cinode)
60838c8a9a5SSteve French {
60938c8a9a5SSteve French 	spin_lock(&cinode->writers_lock);
61038c8a9a5SSteve French 	cinode->writers--;
61138c8a9a5SSteve French 	if (cinode->writers == 0) {
61238c8a9a5SSteve French 		clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
61338c8a9a5SSteve French 		wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS);
61438c8a9a5SSteve French 	}
61538c8a9a5SSteve French 	spin_unlock(&cinode->writers_lock);
61638c8a9a5SSteve French }
61738c8a9a5SSteve French 
61838c8a9a5SSteve French /**
61938c8a9a5SSteve French  * cifs_queue_oplock_break - queue the oplock break handler for cfile
62038c8a9a5SSteve French  * @cfile: The file to break the oplock on
62138c8a9a5SSteve French  *
62238c8a9a5SSteve French  * This function is called from the demultiplex thread when it
62338c8a9a5SSteve French  * receives an oplock break for @cfile.
62438c8a9a5SSteve French  *
62538c8a9a5SSteve French  * Assumes the tcon->open_file_lock is held.
62638c8a9a5SSteve French  * Assumes cfile->file_info_lock is NOT held.
62738c8a9a5SSteve French  */
cifs_queue_oplock_break(struct cifsFileInfo * cfile)62838c8a9a5SSteve French void cifs_queue_oplock_break(struct cifsFileInfo *cfile)
62938c8a9a5SSteve French {
63038c8a9a5SSteve French 	/*
63138c8a9a5SSteve French 	 * Bump the handle refcount now while we hold the
63238c8a9a5SSteve French 	 * open_file_lock to enforce the validity of it for the oplock
63338c8a9a5SSteve French 	 * break handler. The matching put is done at the end of the
63438c8a9a5SSteve French 	 * handler.
63538c8a9a5SSteve French 	 */
63638c8a9a5SSteve French 	cifsFileInfo_get(cfile);
63738c8a9a5SSteve French 
63838c8a9a5SSteve French 	queue_work(cifsoplockd_wq, &cfile->oplock_break);
63938c8a9a5SSteve French }
64038c8a9a5SSteve French 
cifs_done_oplock_break(struct cifsInodeInfo * cinode)64138c8a9a5SSteve French void cifs_done_oplock_break(struct cifsInodeInfo *cinode)
64238c8a9a5SSteve French {
64338c8a9a5SSteve French 	clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags);
64438c8a9a5SSteve French 	wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK);
64538c8a9a5SSteve French }
64638c8a9a5SSteve French 
64738c8a9a5SSteve French bool
backup_cred(struct cifs_sb_info * cifs_sb)64838c8a9a5SSteve French backup_cred(struct cifs_sb_info *cifs_sb)
64938c8a9a5SSteve French {
65038c8a9a5SSteve French 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) {
65138c8a9a5SSteve French 		if (uid_eq(cifs_sb->ctx->backupuid, current_fsuid()))
65238c8a9a5SSteve French 			return true;
65338c8a9a5SSteve French 	}
65438c8a9a5SSteve French 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) {
65538c8a9a5SSteve French 		if (in_group_p(cifs_sb->ctx->backupgid))
65638c8a9a5SSteve French 			return true;
65738c8a9a5SSteve French 	}
65838c8a9a5SSteve French 
65938c8a9a5SSteve French 	return false;
66038c8a9a5SSteve French }
66138c8a9a5SSteve French 
66238c8a9a5SSteve French void
cifs_del_pending_open(struct cifs_pending_open * open)66338c8a9a5SSteve French cifs_del_pending_open(struct cifs_pending_open *open)
66438c8a9a5SSteve French {
66538c8a9a5SSteve French 	spin_lock(&tlink_tcon(open->tlink)->open_file_lock);
66638c8a9a5SSteve French 	list_del(&open->olist);
66738c8a9a5SSteve French 	spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
66838c8a9a5SSteve French }
66938c8a9a5SSteve French 
67038c8a9a5SSteve French void
cifs_add_pending_open_locked(struct cifs_fid * fid,struct tcon_link * tlink,struct cifs_pending_open * open)67138c8a9a5SSteve French cifs_add_pending_open_locked(struct cifs_fid *fid, struct tcon_link *tlink,
67238c8a9a5SSteve French 			     struct cifs_pending_open *open)
67338c8a9a5SSteve French {
67438c8a9a5SSteve French 	memcpy(open->lease_key, fid->lease_key, SMB2_LEASE_KEY_SIZE);
67538c8a9a5SSteve French 	open->oplock = CIFS_OPLOCK_NO_CHANGE;
67638c8a9a5SSteve French 	open->tlink = tlink;
67738c8a9a5SSteve French 	fid->pending_open = open;
67838c8a9a5SSteve French 	list_add_tail(&open->olist, &tlink_tcon(tlink)->pending_opens);
67938c8a9a5SSteve French }
68038c8a9a5SSteve French 
68138c8a9a5SSteve French void
cifs_add_pending_open(struct cifs_fid * fid,struct tcon_link * tlink,struct cifs_pending_open * open)68238c8a9a5SSteve French cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
68338c8a9a5SSteve French 		      struct cifs_pending_open *open)
68438c8a9a5SSteve French {
68538c8a9a5SSteve French 	spin_lock(&tlink_tcon(tlink)->open_file_lock);
68638c8a9a5SSteve French 	cifs_add_pending_open_locked(fid, tlink, open);
68738c8a9a5SSteve French 	spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
68838c8a9a5SSteve French }
68938c8a9a5SSteve French 
69038c8a9a5SSteve French /*
69138c8a9a5SSteve French  * Critical section which runs after acquiring deferred_lock.
69238c8a9a5SSteve French  * As there is no reference count on cifs_deferred_close, pdclose
69338c8a9a5SSteve French  * should not be used outside deferred_lock.
69438c8a9a5SSteve French  */
69538c8a9a5SSteve French bool
cifs_is_deferred_close(struct cifsFileInfo * cfile,struct cifs_deferred_close ** pdclose)69638c8a9a5SSteve French cifs_is_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close **pdclose)
69738c8a9a5SSteve French {
69838c8a9a5SSteve French 	struct cifs_deferred_close *dclose;
69938c8a9a5SSteve French 
70038c8a9a5SSteve French 	list_for_each_entry(dclose, &CIFS_I(d_inode(cfile->dentry))->deferred_closes, dlist) {
70138c8a9a5SSteve French 		if ((dclose->netfid == cfile->fid.netfid) &&
70238c8a9a5SSteve French 			(dclose->persistent_fid == cfile->fid.persistent_fid) &&
70338c8a9a5SSteve French 			(dclose->volatile_fid == cfile->fid.volatile_fid)) {
70438c8a9a5SSteve French 			*pdclose = dclose;
70538c8a9a5SSteve French 			return true;
70638c8a9a5SSteve French 		}
70738c8a9a5SSteve French 	}
70838c8a9a5SSteve French 	return false;
70938c8a9a5SSteve French }
71038c8a9a5SSteve French 
71138c8a9a5SSteve French /*
71238c8a9a5SSteve French  * Critical section which runs after acquiring deferred_lock.
71338c8a9a5SSteve French  */
71438c8a9a5SSteve French void
cifs_add_deferred_close(struct cifsFileInfo * cfile,struct cifs_deferred_close * dclose)71538c8a9a5SSteve French cifs_add_deferred_close(struct cifsFileInfo *cfile, struct cifs_deferred_close *dclose)
71638c8a9a5SSteve French {
71738c8a9a5SSteve French 	bool is_deferred = false;
71838c8a9a5SSteve French 	struct cifs_deferred_close *pdclose;
71938c8a9a5SSteve French 
72038c8a9a5SSteve French 	is_deferred = cifs_is_deferred_close(cfile, &pdclose);
72138c8a9a5SSteve French 	if (is_deferred) {
72238c8a9a5SSteve French 		kfree(dclose);
72338c8a9a5SSteve French 		return;
72438c8a9a5SSteve French 	}
72538c8a9a5SSteve French 
72638c8a9a5SSteve French 	dclose->tlink = cfile->tlink;
72738c8a9a5SSteve French 	dclose->netfid = cfile->fid.netfid;
72838c8a9a5SSteve French 	dclose->persistent_fid = cfile->fid.persistent_fid;
72938c8a9a5SSteve French 	dclose->volatile_fid = cfile->fid.volatile_fid;
73038c8a9a5SSteve French 	list_add_tail(&dclose->dlist, &CIFS_I(d_inode(cfile->dentry))->deferred_closes);
73138c8a9a5SSteve French }
73238c8a9a5SSteve French 
73338c8a9a5SSteve French /*
73438c8a9a5SSteve French  * Critical section which runs after acquiring deferred_lock.
73538c8a9a5SSteve French  */
73638c8a9a5SSteve French void
cifs_del_deferred_close(struct cifsFileInfo * cfile)73738c8a9a5SSteve French cifs_del_deferred_close(struct cifsFileInfo *cfile)
73838c8a9a5SSteve French {
73938c8a9a5SSteve French 	bool is_deferred = false;
74038c8a9a5SSteve French 	struct cifs_deferred_close *dclose;
74138c8a9a5SSteve French 
74238c8a9a5SSteve French 	is_deferred = cifs_is_deferred_close(cfile, &dclose);
74338c8a9a5SSteve French 	if (!is_deferred)
74438c8a9a5SSteve French 		return;
74538c8a9a5SSteve French 	list_del(&dclose->dlist);
74638c8a9a5SSteve French 	kfree(dclose);
74738c8a9a5SSteve French }
74838c8a9a5SSteve French 
74938c8a9a5SSteve French void
cifs_close_deferred_file(struct cifsInodeInfo * cifs_inode)75038c8a9a5SSteve French cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode)
75138c8a9a5SSteve French {
75238c8a9a5SSteve French 	struct cifsFileInfo *cfile = NULL;
75338c8a9a5SSteve French 	struct file_list *tmp_list, *tmp_next_list;
75438c8a9a5SSteve French 	struct list_head file_head;
75538c8a9a5SSteve French 
75638c8a9a5SSteve French 	if (cifs_inode == NULL)
75738c8a9a5SSteve French 		return;
75838c8a9a5SSteve French 
75938c8a9a5SSteve French 	INIT_LIST_HEAD(&file_head);
76038c8a9a5SSteve French 	spin_lock(&cifs_inode->open_file_lock);
76138c8a9a5SSteve French 	list_for_each_entry(cfile, &cifs_inode->openFileList, flist) {
76238c8a9a5SSteve French 		if (delayed_work_pending(&cfile->deferred)) {
76338c8a9a5SSteve French 			if (cancel_delayed_work(&cfile->deferred)) {
76438c8a9a5SSteve French 				spin_lock(&cifs_inode->deferred_lock);
76538c8a9a5SSteve French 				cifs_del_deferred_close(cfile);
76638c8a9a5SSteve French 				spin_unlock(&cifs_inode->deferred_lock);
76738c8a9a5SSteve French 
76838c8a9a5SSteve French 				tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
76938c8a9a5SSteve French 				if (tmp_list == NULL)
77038c8a9a5SSteve French 					break;
77138c8a9a5SSteve French 				tmp_list->cfile = cfile;
77238c8a9a5SSteve French 				list_add_tail(&tmp_list->list, &file_head);
77338c8a9a5SSteve French 			}
77438c8a9a5SSteve French 		}
77538c8a9a5SSteve French 	}
77638c8a9a5SSteve French 	spin_unlock(&cifs_inode->open_file_lock);
77738c8a9a5SSteve French 
77838c8a9a5SSteve French 	list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
77938c8a9a5SSteve French 		_cifsFileInfo_put(tmp_list->cfile, false, false);
78038c8a9a5SSteve French 		list_del(&tmp_list->list);
78138c8a9a5SSteve French 		kfree(tmp_list);
78238c8a9a5SSteve French 	}
78338c8a9a5SSteve French }
78438c8a9a5SSteve French 
78538c8a9a5SSteve French void
cifs_close_all_deferred_files(struct cifs_tcon * tcon)78638c8a9a5SSteve French cifs_close_all_deferred_files(struct cifs_tcon *tcon)
78738c8a9a5SSteve French {
78838c8a9a5SSteve French 	struct cifsFileInfo *cfile;
78938c8a9a5SSteve French 	struct file_list *tmp_list, *tmp_next_list;
79038c8a9a5SSteve French 	struct list_head file_head;
79138c8a9a5SSteve French 
79238c8a9a5SSteve French 	INIT_LIST_HEAD(&file_head);
79338c8a9a5SSteve French 	spin_lock(&tcon->open_file_lock);
79438c8a9a5SSteve French 	list_for_each_entry(cfile, &tcon->openFileList, tlist) {
79538c8a9a5SSteve French 		if (delayed_work_pending(&cfile->deferred)) {
79638c8a9a5SSteve French 			if (cancel_delayed_work(&cfile->deferred)) {
79738c8a9a5SSteve French 				spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
79838c8a9a5SSteve French 				cifs_del_deferred_close(cfile);
79938c8a9a5SSteve French 				spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
80038c8a9a5SSteve French 
80138c8a9a5SSteve French 				tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
80238c8a9a5SSteve French 				if (tmp_list == NULL)
80338c8a9a5SSteve French 					break;
80438c8a9a5SSteve French 				tmp_list->cfile = cfile;
80538c8a9a5SSteve French 				list_add_tail(&tmp_list->list, &file_head);
80638c8a9a5SSteve French 			}
80738c8a9a5SSteve French 		}
80838c8a9a5SSteve French 	}
80938c8a9a5SSteve French 	spin_unlock(&tcon->open_file_lock);
81038c8a9a5SSteve French 
81138c8a9a5SSteve French 	list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
81238c8a9a5SSteve French 		_cifsFileInfo_put(tmp_list->cfile, true, false);
81338c8a9a5SSteve French 		list_del(&tmp_list->list);
81438c8a9a5SSteve French 		kfree(tmp_list);
81538c8a9a5SSteve French 	}
81638c8a9a5SSteve French }
81738c8a9a5SSteve French void
cifs_close_deferred_file_under_dentry(struct cifs_tcon * tcon,const char * path)81838c8a9a5SSteve French cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon, const char *path)
81938c8a9a5SSteve French {
82038c8a9a5SSteve French 	struct cifsFileInfo *cfile;
82138c8a9a5SSteve French 	struct file_list *tmp_list, *tmp_next_list;
82238c8a9a5SSteve French 	struct list_head file_head;
82338c8a9a5SSteve French 	void *page;
82438c8a9a5SSteve French 	const char *full_path;
82538c8a9a5SSteve French 
82638c8a9a5SSteve French 	INIT_LIST_HEAD(&file_head);
82738c8a9a5SSteve French 	page = alloc_dentry_path();
82838c8a9a5SSteve French 	spin_lock(&tcon->open_file_lock);
82938c8a9a5SSteve French 	list_for_each_entry(cfile, &tcon->openFileList, tlist) {
83038c8a9a5SSteve French 		full_path = build_path_from_dentry(cfile->dentry, page);
83138c8a9a5SSteve French 		if (strstr(full_path, path)) {
83238c8a9a5SSteve French 			if (delayed_work_pending(&cfile->deferred)) {
83338c8a9a5SSteve French 				if (cancel_delayed_work(&cfile->deferred)) {
83438c8a9a5SSteve French 					spin_lock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
83538c8a9a5SSteve French 					cifs_del_deferred_close(cfile);
83638c8a9a5SSteve French 					spin_unlock(&CIFS_I(d_inode(cfile->dentry))->deferred_lock);
83738c8a9a5SSteve French 
83838c8a9a5SSteve French 					tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC);
83938c8a9a5SSteve French 					if (tmp_list == NULL)
84038c8a9a5SSteve French 						break;
84138c8a9a5SSteve French 					tmp_list->cfile = cfile;
84238c8a9a5SSteve French 					list_add_tail(&tmp_list->list, &file_head);
84338c8a9a5SSteve French 				}
84438c8a9a5SSteve French 			}
84538c8a9a5SSteve French 		}
84638c8a9a5SSteve French 	}
84738c8a9a5SSteve French 	spin_unlock(&tcon->open_file_lock);
84838c8a9a5SSteve French 
84938c8a9a5SSteve French 	list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) {
85038c8a9a5SSteve French 		_cifsFileInfo_put(tmp_list->cfile, true, false);
85138c8a9a5SSteve French 		list_del(&tmp_list->list);
85238c8a9a5SSteve French 		kfree(tmp_list);
85338c8a9a5SSteve French 	}
85438c8a9a5SSteve French 	free_dentry_path(page);
85538c8a9a5SSteve French }
85638c8a9a5SSteve French 
857b6e27f7fSSteve French /*
858b6e27f7fSSteve French  * If a dentry has been deleted, all corresponding open handles should know that
859b6e27f7fSSteve French  * so that we do not defer close them.
860b6e27f7fSSteve French  */
cifs_mark_open_handles_for_deleted_file(struct inode * inode,const char * path)861b6e27f7fSSteve French void cifs_mark_open_handles_for_deleted_file(struct inode *inode,
862b6e27f7fSSteve French 					     const char *path)
863b6e27f7fSSteve French {
864b6e27f7fSSteve French 	struct cifsFileInfo *cfile;
865b6e27f7fSSteve French 	void *page;
866b6e27f7fSSteve French 	const char *full_path;
867b6e27f7fSSteve French 	struct cifsInodeInfo *cinode = CIFS_I(inode);
868b6e27f7fSSteve French 
869b6e27f7fSSteve French 	page = alloc_dentry_path();
870b6e27f7fSSteve French 	spin_lock(&cinode->open_file_lock);
871b6e27f7fSSteve French 
872b6e27f7fSSteve French 	/*
873b6e27f7fSSteve French 	 * note: we need to construct path from dentry and compare only if the
874b6e27f7fSSteve French 	 * inode has any hardlinks. When number of hardlinks is 1, we can just
875b6e27f7fSSteve French 	 * mark all open handles since they are going to be from the same file.
876b6e27f7fSSteve French 	 */
877b6e27f7fSSteve French 	if (inode->i_nlink > 1) {
878b6e27f7fSSteve French 		list_for_each_entry(cfile, &cinode->openFileList, flist) {
879b6e27f7fSSteve French 			full_path = build_path_from_dentry(cfile->dentry, page);
880b6e27f7fSSteve French 			if (!IS_ERR(full_path) && strcmp(full_path, path) == 0)
881b6e27f7fSSteve French 				cfile->status_file_deleted = true;
882b6e27f7fSSteve French 		}
883b6e27f7fSSteve French 	} else {
884b6e27f7fSSteve French 		list_for_each_entry(cfile, &cinode->openFileList, flist)
885b6e27f7fSSteve French 			cfile->status_file_deleted = true;
886b6e27f7fSSteve French 	}
887b6e27f7fSSteve French 	spin_unlock(&cinode->open_file_lock);
888b6e27f7fSSteve French 	free_dentry_path(page);
889b6e27f7fSSteve French }
890b6e27f7fSSteve French 
89138c8a9a5SSteve French /* parses DFS referral V3 structure
89238c8a9a5SSteve French  * caller is responsible for freeing target_nodes
89338c8a9a5SSteve French  * returns:
89438c8a9a5SSteve French  * - on success - 0
89538c8a9a5SSteve French  * - on failure - errno
89638c8a9a5SSteve French  */
89738c8a9a5SSteve French int
parse_dfs_referrals(struct get_dfs_referral_rsp * rsp,u32 rsp_size,unsigned int * num_of_nodes,struct dfs_info3_param ** target_nodes,const struct nls_table * nls_codepage,int remap,const char * searchName,bool is_unicode)89838c8a9a5SSteve French parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
89938c8a9a5SSteve French 		    unsigned int *num_of_nodes,
90038c8a9a5SSteve French 		    struct dfs_info3_param **target_nodes,
90138c8a9a5SSteve French 		    const struct nls_table *nls_codepage, int remap,
90238c8a9a5SSteve French 		    const char *searchName, bool is_unicode)
90338c8a9a5SSteve French {
90438c8a9a5SSteve French 	int i, rc = 0;
90538c8a9a5SSteve French 	char *data_end;
90638c8a9a5SSteve French 	struct dfs_referral_level_3 *ref;
90738c8a9a5SSteve French 
90838c8a9a5SSteve French 	*num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals);
90938c8a9a5SSteve French 
91038c8a9a5SSteve French 	if (*num_of_nodes < 1) {
91138c8a9a5SSteve French 		cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
91238c8a9a5SSteve French 			 *num_of_nodes);
91338c8a9a5SSteve French 		rc = -EINVAL;
91438c8a9a5SSteve French 		goto parse_DFS_referrals_exit;
91538c8a9a5SSteve French 	}
91638c8a9a5SSteve French 
91738c8a9a5SSteve French 	ref = (struct dfs_referral_level_3 *) &(rsp->referrals);
91838c8a9a5SSteve French 	if (ref->VersionNumber != cpu_to_le16(3)) {
91938c8a9a5SSteve French 		cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
92038c8a9a5SSteve French 			 le16_to_cpu(ref->VersionNumber));
92138c8a9a5SSteve French 		rc = -EINVAL;
92238c8a9a5SSteve French 		goto parse_DFS_referrals_exit;
92338c8a9a5SSteve French 	}
92438c8a9a5SSteve French 
92538c8a9a5SSteve French 	/* get the upper boundary of the resp buffer */
92638c8a9a5SSteve French 	data_end = (char *)rsp + rsp_size;
92738c8a9a5SSteve French 
92838c8a9a5SSteve French 	cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
92938c8a9a5SSteve French 		 *num_of_nodes, le32_to_cpu(rsp->DFSFlags));
93038c8a9a5SSteve French 
93138c8a9a5SSteve French 	*target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
93238c8a9a5SSteve French 				GFP_KERNEL);
93338c8a9a5SSteve French 	if (*target_nodes == NULL) {
93438c8a9a5SSteve French 		rc = -ENOMEM;
93538c8a9a5SSteve French 		goto parse_DFS_referrals_exit;
93638c8a9a5SSteve French 	}
93738c8a9a5SSteve French 
93838c8a9a5SSteve French 	/* collect necessary data from referrals */
93938c8a9a5SSteve French 	for (i = 0; i < *num_of_nodes; i++) {
94038c8a9a5SSteve French 		char *temp;
94138c8a9a5SSteve French 		int max_len;
94238c8a9a5SSteve French 		struct dfs_info3_param *node = (*target_nodes)+i;
94338c8a9a5SSteve French 
94438c8a9a5SSteve French 		node->flags = le32_to_cpu(rsp->DFSFlags);
94538c8a9a5SSteve French 		if (is_unicode) {
94638c8a9a5SSteve French 			__le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
94738c8a9a5SSteve French 						GFP_KERNEL);
94838c8a9a5SSteve French 			if (tmp == NULL) {
94938c8a9a5SSteve French 				rc = -ENOMEM;
95038c8a9a5SSteve French 				goto parse_DFS_referrals_exit;
95138c8a9a5SSteve French 			}
95238c8a9a5SSteve French 			cifsConvertToUTF16((__le16 *) tmp, searchName,
95338c8a9a5SSteve French 					   PATH_MAX, nls_codepage, remap);
95438c8a9a5SSteve French 			node->path_consumed = cifs_utf16_bytes(tmp,
95538c8a9a5SSteve French 					le16_to_cpu(rsp->PathConsumed),
95638c8a9a5SSteve French 					nls_codepage);
95738c8a9a5SSteve French 			kfree(tmp);
95838c8a9a5SSteve French 		} else
95938c8a9a5SSteve French 			node->path_consumed = le16_to_cpu(rsp->PathConsumed);
96038c8a9a5SSteve French 
96138c8a9a5SSteve French 		node->server_type = le16_to_cpu(ref->ServerType);
96238c8a9a5SSteve French 		node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
96338c8a9a5SSteve French 
96438c8a9a5SSteve French 		/* copy DfsPath */
96538c8a9a5SSteve French 		temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
96638c8a9a5SSteve French 		max_len = data_end - temp;
96738c8a9a5SSteve French 		node->path_name = cifs_strndup_from_utf16(temp, max_len,
96838c8a9a5SSteve French 						is_unicode, nls_codepage);
96938c8a9a5SSteve French 		if (!node->path_name) {
97038c8a9a5SSteve French 			rc = -ENOMEM;
97138c8a9a5SSteve French 			goto parse_DFS_referrals_exit;
97238c8a9a5SSteve French 		}
97338c8a9a5SSteve French 
97438c8a9a5SSteve French 		/* copy link target UNC */
97538c8a9a5SSteve French 		temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
97638c8a9a5SSteve French 		max_len = data_end - temp;
97738c8a9a5SSteve French 		node->node_name = cifs_strndup_from_utf16(temp, max_len,
97838c8a9a5SSteve French 						is_unicode, nls_codepage);
97938c8a9a5SSteve French 		if (!node->node_name) {
98038c8a9a5SSteve French 			rc = -ENOMEM;
98138c8a9a5SSteve French 			goto parse_DFS_referrals_exit;
98238c8a9a5SSteve French 		}
98338c8a9a5SSteve French 
98438c8a9a5SSteve French 		node->ttl = le32_to_cpu(ref->TimeToLive);
98538c8a9a5SSteve French 
98638c8a9a5SSteve French 		ref++;
98738c8a9a5SSteve French 	}
98838c8a9a5SSteve French 
98938c8a9a5SSteve French parse_DFS_referrals_exit:
99038c8a9a5SSteve French 	if (rc) {
99138c8a9a5SSteve French 		free_dfs_info_array(*target_nodes, *num_of_nodes);
99238c8a9a5SSteve French 		*target_nodes = NULL;
99338c8a9a5SSteve French 		*num_of_nodes = 0;
99438c8a9a5SSteve French 	}
99538c8a9a5SSteve French 	return rc;
99638c8a9a5SSteve French }
99738c8a9a5SSteve French 
99838c8a9a5SSteve French struct cifs_aio_ctx *
cifs_aio_ctx_alloc(void)99938c8a9a5SSteve French cifs_aio_ctx_alloc(void)
100038c8a9a5SSteve French {
100138c8a9a5SSteve French 	struct cifs_aio_ctx *ctx;
100238c8a9a5SSteve French 
100338c8a9a5SSteve French 	/*
100438c8a9a5SSteve French 	 * Must use kzalloc to initialize ctx->bv to NULL and ctx->direct_io
100538c8a9a5SSteve French 	 * to false so that we know when we have to unreference pages within
100638c8a9a5SSteve French 	 * cifs_aio_ctx_release()
100738c8a9a5SSteve French 	 */
100838c8a9a5SSteve French 	ctx = kzalloc(sizeof(struct cifs_aio_ctx), GFP_KERNEL);
100938c8a9a5SSteve French 	if (!ctx)
101038c8a9a5SSteve French 		return NULL;
101138c8a9a5SSteve French 
101238c8a9a5SSteve French 	INIT_LIST_HEAD(&ctx->list);
101338c8a9a5SSteve French 	mutex_init(&ctx->aio_mutex);
101438c8a9a5SSteve French 	init_completion(&ctx->done);
101538c8a9a5SSteve French 	kref_init(&ctx->refcount);
101638c8a9a5SSteve French 	return ctx;
101738c8a9a5SSteve French }
101838c8a9a5SSteve French 
101938c8a9a5SSteve French void
cifs_aio_ctx_release(struct kref * refcount)102038c8a9a5SSteve French cifs_aio_ctx_release(struct kref *refcount)
102138c8a9a5SSteve French {
102238c8a9a5SSteve French 	struct cifs_aio_ctx *ctx = container_of(refcount,
102338c8a9a5SSteve French 					struct cifs_aio_ctx, refcount);
102438c8a9a5SSteve French 
102538c8a9a5SSteve French 	cifsFileInfo_put(ctx->cfile);
102638c8a9a5SSteve French 
102738c8a9a5SSteve French 	/*
102838c8a9a5SSteve French 	 * ctx->bv is only set if setup_aio_ctx_iter() was call successfuly
102938c8a9a5SSteve French 	 * which means that iov_iter_extract_pages() was a success and thus
103038c8a9a5SSteve French 	 * that we may have references or pins on pages that we need to
103138c8a9a5SSteve French 	 * release.
103238c8a9a5SSteve French 	 */
103338c8a9a5SSteve French 	if (ctx->bv) {
103438c8a9a5SSteve French 		if (ctx->should_dirty || ctx->bv_need_unpin) {
103538c8a9a5SSteve French 			unsigned int i;
103638c8a9a5SSteve French 
103738c8a9a5SSteve French 			for (i = 0; i < ctx->nr_pinned_pages; i++) {
103838c8a9a5SSteve French 				struct page *page = ctx->bv[i].bv_page;
103938c8a9a5SSteve French 
104038c8a9a5SSteve French 				if (ctx->should_dirty)
104138c8a9a5SSteve French 					set_page_dirty(page);
104238c8a9a5SSteve French 				if (ctx->bv_need_unpin)
104338c8a9a5SSteve French 					unpin_user_page(page);
104438c8a9a5SSteve French 			}
104538c8a9a5SSteve French 		}
104638c8a9a5SSteve French 		kvfree(ctx->bv);
104738c8a9a5SSteve French 	}
104838c8a9a5SSteve French 
104938c8a9a5SSteve French 	kfree(ctx);
105038c8a9a5SSteve French }
105138c8a9a5SSteve French 
105238c8a9a5SSteve French /**
105338c8a9a5SSteve French  * cifs_alloc_hash - allocate hash and hash context together
105438c8a9a5SSteve French  * @name: The name of the crypto hash algo
105538c8a9a5SSteve French  * @sdesc: SHASH descriptor where to put the pointer to the hash TFM
105638c8a9a5SSteve French  *
105738c8a9a5SSteve French  * The caller has to make sure @sdesc is initialized to either NULL or
105838c8a9a5SSteve French  * a valid context. It can be freed via cifs_free_hash().
105938c8a9a5SSteve French  */
106038c8a9a5SSteve French int
cifs_alloc_hash(const char * name,struct shash_desc ** sdesc)106138c8a9a5SSteve French cifs_alloc_hash(const char *name, struct shash_desc **sdesc)
106238c8a9a5SSteve French {
106338c8a9a5SSteve French 	int rc = 0;
106438c8a9a5SSteve French 	struct crypto_shash *alg = NULL;
106538c8a9a5SSteve French 
106638c8a9a5SSteve French 	if (*sdesc)
106738c8a9a5SSteve French 		return 0;
106838c8a9a5SSteve French 
106938c8a9a5SSteve French 	alg = crypto_alloc_shash(name, 0, 0);
107038c8a9a5SSteve French 	if (IS_ERR(alg)) {
107138c8a9a5SSteve French 		cifs_dbg(VFS, "Could not allocate shash TFM '%s'\n", name);
107238c8a9a5SSteve French 		rc = PTR_ERR(alg);
107338c8a9a5SSteve French 		*sdesc = NULL;
107438c8a9a5SSteve French 		return rc;
107538c8a9a5SSteve French 	}
107638c8a9a5SSteve French 
107738c8a9a5SSteve French 	*sdesc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(alg), GFP_KERNEL);
107838c8a9a5SSteve French 	if (*sdesc == NULL) {
107938c8a9a5SSteve French 		cifs_dbg(VFS, "no memory left to allocate shash TFM '%s'\n", name);
108038c8a9a5SSteve French 		crypto_free_shash(alg);
108138c8a9a5SSteve French 		return -ENOMEM;
108238c8a9a5SSteve French 	}
108338c8a9a5SSteve French 
108438c8a9a5SSteve French 	(*sdesc)->tfm = alg;
108538c8a9a5SSteve French 	return 0;
108638c8a9a5SSteve French }
108738c8a9a5SSteve French 
108838c8a9a5SSteve French /**
108938c8a9a5SSteve French  * cifs_free_hash - free hash and hash context together
109038c8a9a5SSteve French  * @sdesc: Where to find the pointer to the hash TFM
109138c8a9a5SSteve French  *
109238c8a9a5SSteve French  * Freeing a NULL descriptor is safe.
109338c8a9a5SSteve French  */
109438c8a9a5SSteve French void
cifs_free_hash(struct shash_desc ** sdesc)109538c8a9a5SSteve French cifs_free_hash(struct shash_desc **sdesc)
109638c8a9a5SSteve French {
109738c8a9a5SSteve French 	if (unlikely(!sdesc) || !*sdesc)
109838c8a9a5SSteve French 		return;
109938c8a9a5SSteve French 
110038c8a9a5SSteve French 	if ((*sdesc)->tfm) {
110138c8a9a5SSteve French 		crypto_free_shash((*sdesc)->tfm);
110238c8a9a5SSteve French 		(*sdesc)->tfm = NULL;
110338c8a9a5SSteve French 	}
110438c8a9a5SSteve French 
110538c8a9a5SSteve French 	kfree_sensitive(*sdesc);
110638c8a9a5SSteve French 	*sdesc = NULL;
110738c8a9a5SSteve French }
110838c8a9a5SSteve French 
extract_unc_hostname(const char * unc,const char ** h,size_t * len)110938c8a9a5SSteve French void extract_unc_hostname(const char *unc, const char **h, size_t *len)
111038c8a9a5SSteve French {
111138c8a9a5SSteve French 	const char *end;
111238c8a9a5SSteve French 
111338c8a9a5SSteve French 	/* skip initial slashes */
111438c8a9a5SSteve French 	while (*unc && (*unc == '\\' || *unc == '/'))
111538c8a9a5SSteve French 		unc++;
111638c8a9a5SSteve French 
111738c8a9a5SSteve French 	end = unc;
111838c8a9a5SSteve French 
111938c8a9a5SSteve French 	while (*end && !(*end == '\\' || *end == '/'))
112038c8a9a5SSteve French 		end++;
112138c8a9a5SSteve French 
112238c8a9a5SSteve French 	*h = unc;
112338c8a9a5SSteve French 	*len = end - unc;
112438c8a9a5SSteve French }
112538c8a9a5SSteve French 
112638c8a9a5SSteve French /**
112738c8a9a5SSteve French  * copy_path_name - copy src path to dst, possibly truncating
112838c8a9a5SSteve French  * @dst: The destination buffer
112938c8a9a5SSteve French  * @src: The source name
113038c8a9a5SSteve French  *
113138c8a9a5SSteve French  * returns number of bytes written (including trailing nul)
113238c8a9a5SSteve French  */
copy_path_name(char * dst,const char * src)113338c8a9a5SSteve French int copy_path_name(char *dst, const char *src)
113438c8a9a5SSteve French {
113538c8a9a5SSteve French 	int name_len;
113638c8a9a5SSteve French 
113738c8a9a5SSteve French 	/*
113838c8a9a5SSteve French 	 * PATH_MAX includes nul, so if strlen(src) >= PATH_MAX it
113938c8a9a5SSteve French 	 * will truncate and strlen(dst) will be PATH_MAX-1
114038c8a9a5SSteve French 	 */
114138c8a9a5SSteve French 	name_len = strscpy(dst, src, PATH_MAX);
114238c8a9a5SSteve French 	if (WARN_ON_ONCE(name_len < 0))
114338c8a9a5SSteve French 		name_len = PATH_MAX-1;
114438c8a9a5SSteve French 
114538c8a9a5SSteve French 	/* we count the trailing nul */
114638c8a9a5SSteve French 	name_len++;
114738c8a9a5SSteve French 	return name_len;
114838c8a9a5SSteve French }
114938c8a9a5SSteve French 
115038c8a9a5SSteve French struct super_cb_data {
115138c8a9a5SSteve French 	void *data;
115238c8a9a5SSteve French 	struct super_block *sb;
115338c8a9a5SSteve French };
115438c8a9a5SSteve French 
tcon_super_cb(struct super_block * sb,void * arg)11553ae872deSPaulo Alcantara static void tcon_super_cb(struct super_block *sb, void *arg)
115638c8a9a5SSteve French {
115738c8a9a5SSteve French 	struct super_cb_data *sd = arg;
115838c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb;
11593ae872deSPaulo Alcantara 	struct cifs_tcon *t1 = sd->data, *t2;
116038c8a9a5SSteve French 
116138c8a9a5SSteve French 	if (sd->sb)
116238c8a9a5SSteve French 		return;
116338c8a9a5SSteve French 
116438c8a9a5SSteve French 	cifs_sb = CIFS_SB(sb);
11653ae872deSPaulo Alcantara 	t2 = cifs_sb_master_tcon(cifs_sb);
11663ae872deSPaulo Alcantara 
11673ae872deSPaulo Alcantara 	spin_lock(&t2->tc_lock);
11683ae872deSPaulo Alcantara 	if (t1->ses == t2->ses &&
11693ae872deSPaulo Alcantara 	    t1->ses->server == t2->ses->server &&
11703ae872deSPaulo Alcantara 	    t2->origin_fullpath &&
11713ae872deSPaulo Alcantara 	    dfs_src_pathname_equal(t2->origin_fullpath, t1->origin_fullpath))
117238c8a9a5SSteve French 		sd->sb = sb;
11733ae872deSPaulo Alcantara 	spin_unlock(&t2->tc_lock);
117438c8a9a5SSteve French }
117538c8a9a5SSteve French 
__cifs_get_super(void (* f)(struct super_block *,void *),void * data)117638c8a9a5SSteve French static struct super_block *__cifs_get_super(void (*f)(struct super_block *, void *),
117738c8a9a5SSteve French 					    void *data)
117838c8a9a5SSteve French {
117938c8a9a5SSteve French 	struct super_cb_data sd = {
118038c8a9a5SSteve French 		.data = data,
118138c8a9a5SSteve French 		.sb = NULL,
118238c8a9a5SSteve French 	};
118338c8a9a5SSteve French 	struct file_system_type **fs_type = (struct file_system_type *[]) {
118438c8a9a5SSteve French 		&cifs_fs_type, &smb3_fs_type, NULL,
118538c8a9a5SSteve French 	};
118638c8a9a5SSteve French 
118738c8a9a5SSteve French 	for (; *fs_type; fs_type++) {
118838c8a9a5SSteve French 		iterate_supers_type(*fs_type, f, &sd);
118938c8a9a5SSteve French 		if (sd.sb) {
119038c8a9a5SSteve French 			/*
119138c8a9a5SSteve French 			 * Grab an active reference in order to prevent automounts (DFS links)
119238c8a9a5SSteve French 			 * of expiring and then freeing up our cifs superblock pointer while
119338c8a9a5SSteve French 			 * we're doing failover.
119438c8a9a5SSteve French 			 */
119538c8a9a5SSteve French 			cifs_sb_active(sd.sb);
119638c8a9a5SSteve French 			return sd.sb;
119738c8a9a5SSteve French 		}
119838c8a9a5SSteve French 	}
11993ae872deSPaulo Alcantara 	pr_warn_once("%s: could not find dfs superblock\n", __func__);
120038c8a9a5SSteve French 	return ERR_PTR(-EINVAL);
120138c8a9a5SSteve French }
120238c8a9a5SSteve French 
__cifs_put_super(struct super_block * sb)120338c8a9a5SSteve French static void __cifs_put_super(struct super_block *sb)
120438c8a9a5SSteve French {
120538c8a9a5SSteve French 	if (!IS_ERR_OR_NULL(sb))
120638c8a9a5SSteve French 		cifs_sb_deactive(sb);
120738c8a9a5SSteve French }
120838c8a9a5SSteve French 
cifs_get_dfs_tcon_super(struct cifs_tcon * tcon)12093ae872deSPaulo Alcantara struct super_block *cifs_get_dfs_tcon_super(struct cifs_tcon *tcon)
121038c8a9a5SSteve French {
12113ae872deSPaulo Alcantara 	spin_lock(&tcon->tc_lock);
12123ae872deSPaulo Alcantara 	if (!tcon->origin_fullpath) {
12133ae872deSPaulo Alcantara 		spin_unlock(&tcon->tc_lock);
12143ae872deSPaulo Alcantara 		return ERR_PTR(-ENOENT);
12153ae872deSPaulo Alcantara 	}
12163ae872deSPaulo Alcantara 	spin_unlock(&tcon->tc_lock);
12173ae872deSPaulo Alcantara 	return __cifs_get_super(tcon_super_cb, tcon);
121838c8a9a5SSteve French }
121938c8a9a5SSteve French 
cifs_put_tcp_super(struct super_block * sb)122038c8a9a5SSteve French void cifs_put_tcp_super(struct super_block *sb)
122138c8a9a5SSteve French {
122238c8a9a5SSteve French 	__cifs_put_super(sb);
122338c8a9a5SSteve French }
122438c8a9a5SSteve French 
122538c8a9a5SSteve French #ifdef CONFIG_CIFS_DFS_UPCALL
match_target_ip(struct TCP_Server_Info * server,const char * share,size_t share_len,bool * result)122638c8a9a5SSteve French int match_target_ip(struct TCP_Server_Info *server,
122738c8a9a5SSteve French 		    const char *share, size_t share_len,
122838c8a9a5SSteve French 		    bool *result)
122938c8a9a5SSteve French {
123038c8a9a5SSteve French 	int rc;
123138c8a9a5SSteve French 	char *target;
123238c8a9a5SSteve French 	struct sockaddr_storage ss;
123338c8a9a5SSteve French 
123438c8a9a5SSteve French 	*result = false;
123538c8a9a5SSteve French 
123638c8a9a5SSteve French 	target = kzalloc(share_len + 3, GFP_KERNEL);
123738c8a9a5SSteve French 	if (!target)
123838c8a9a5SSteve French 		return -ENOMEM;
123938c8a9a5SSteve French 
124038c8a9a5SSteve French 	scnprintf(target, share_len + 3, "\\\\%.*s", (int)share_len, share);
124138c8a9a5SSteve French 
124238c8a9a5SSteve French 	cifs_dbg(FYI, "%s: target name: %s\n", __func__, target + 2);
124338c8a9a5SSteve French 
124438c8a9a5SSteve French 	rc = dns_resolve_server_name_to_ip(target, (struct sockaddr *)&ss, NULL);
124538c8a9a5SSteve French 	kfree(target);
124638c8a9a5SSteve French 
124738c8a9a5SSteve French 	if (rc < 0)
124838c8a9a5SSteve French 		return rc;
124938c8a9a5SSteve French 
125038c8a9a5SSteve French 	spin_lock(&server->srv_lock);
125138c8a9a5SSteve French 	*result = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr, (struct sockaddr *)&ss);
125238c8a9a5SSteve French 	spin_unlock(&server->srv_lock);
125338c8a9a5SSteve French 	cifs_dbg(FYI, "%s: ip addresses match: %u\n", __func__, *result);
125438c8a9a5SSteve French 	return 0;
125538c8a9a5SSteve French }
125638c8a9a5SSteve French 
cifs_update_super_prepath(struct cifs_sb_info * cifs_sb,char * prefix)125738c8a9a5SSteve French int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix)
125838c8a9a5SSteve French {
125949024ec8SPaulo Alcantara 	int rc;
126049024ec8SPaulo Alcantara 
126138c8a9a5SSteve French 	kfree(cifs_sb->prepath);
126249024ec8SPaulo Alcantara 	cifs_sb->prepath = NULL;
126338c8a9a5SSteve French 
126438c8a9a5SSteve French 	if (prefix && *prefix) {
126538c8a9a5SSteve French 		cifs_sb->prepath = cifs_sanitize_prepath(prefix, GFP_ATOMIC);
126649024ec8SPaulo Alcantara 		if (IS_ERR(cifs_sb->prepath)) {
126749024ec8SPaulo Alcantara 			rc = PTR_ERR(cifs_sb->prepath);
126838c8a9a5SSteve French 			cifs_sb->prepath = NULL;
126949024ec8SPaulo Alcantara 			return rc;
127049024ec8SPaulo Alcantara 		}
127149024ec8SPaulo Alcantara 		if (cifs_sb->prepath)
127249024ec8SPaulo Alcantara 			convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
127349024ec8SPaulo Alcantara 	}
127438c8a9a5SSteve French 
127538c8a9a5SSteve French 	cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
127638c8a9a5SSteve French 	return 0;
127738c8a9a5SSteve French }
127838c8a9a5SSteve French 
127938c8a9a5SSteve French /*
128038c8a9a5SSteve French  * Handle weird Windows SMB server behaviour. It responds with
128138c8a9a5SSteve French  * STATUS_OBJECT_NAME_INVALID code to SMB2 QUERY_INFO request for
128238c8a9a5SSteve French  * "\<server>\<dfsname>\<linkpath>" DFS reference, where <dfsname> contains
128338c8a9a5SSteve French  * non-ASCII unicode symbols.
128438c8a9a5SSteve French  */
cifs_inval_name_dfs_link_error(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,bool * islink)128538c8a9a5SSteve French int cifs_inval_name_dfs_link_error(const unsigned int xid,
128638c8a9a5SSteve French 				   struct cifs_tcon *tcon,
128738c8a9a5SSteve French 				   struct cifs_sb_info *cifs_sb,
128838c8a9a5SSteve French 				   const char *full_path,
128938c8a9a5SSteve French 				   bool *islink)
129038c8a9a5SSteve French {
1291*c0f767deSGleb Korobeynikov 	struct TCP_Server_Info *server = tcon->ses->server;
129238c8a9a5SSteve French 	struct cifs_ses *ses = tcon->ses;
129338c8a9a5SSteve French 	size_t len;
129438c8a9a5SSteve French 	char *path;
129538c8a9a5SSteve French 	char *ref_path;
129638c8a9a5SSteve French 
129738c8a9a5SSteve French 	*islink = false;
129838c8a9a5SSteve French 
129938c8a9a5SSteve French 	/*
130038c8a9a5SSteve French 	 * Fast path - skip check when @full_path doesn't have a prefix path to
130138c8a9a5SSteve French 	 * look up or tcon is not DFS.
130238c8a9a5SSteve French 	 */
130338c8a9a5SSteve French 	if (strlen(full_path) < 2 || !cifs_sb ||
130438c8a9a5SSteve French 	    (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) ||
13053ae872deSPaulo Alcantara 	    !is_tcon_dfs(tcon))
130638c8a9a5SSteve French 		return 0;
130738c8a9a5SSteve French 
1308*c0f767deSGleb Korobeynikov 	spin_lock(&server->srv_lock);
1309*c0f767deSGleb Korobeynikov 	if (!server->leaf_fullpath) {
1310*c0f767deSGleb Korobeynikov 		spin_unlock(&server->srv_lock);
13113ae872deSPaulo Alcantara 		return 0;
13123ae872deSPaulo Alcantara 	}
1313*c0f767deSGleb Korobeynikov 	spin_unlock(&server->srv_lock);
13143ae872deSPaulo Alcantara 
131538c8a9a5SSteve French 	/*
131638c8a9a5SSteve French 	 * Slow path - tcon is DFS and @full_path has prefix path, so attempt
131738c8a9a5SSteve French 	 * to get a referral to figure out whether it is an DFS link.
131838c8a9a5SSteve French 	 */
131938c8a9a5SSteve French 	len = strnlen(tcon->tree_name, MAX_TREE_SIZE + 1) + strlen(full_path) + 1;
132038c8a9a5SSteve French 	path = kmalloc(len, GFP_KERNEL);
132138c8a9a5SSteve French 	if (!path)
132238c8a9a5SSteve French 		return -ENOMEM;
132338c8a9a5SSteve French 
132438c8a9a5SSteve French 	scnprintf(path, len, "%s%s", tcon->tree_name, full_path);
132538c8a9a5SSteve French 	ref_path = dfs_cache_canonical_path(path + 1, cifs_sb->local_nls,
132638c8a9a5SSteve French 					    cifs_remap(cifs_sb));
132738c8a9a5SSteve French 	kfree(path);
132838c8a9a5SSteve French 
132938c8a9a5SSteve French 	if (IS_ERR(ref_path)) {
133038c8a9a5SSteve French 		if (PTR_ERR(ref_path) != -EINVAL)
133138c8a9a5SSteve French 			return PTR_ERR(ref_path);
133238c8a9a5SSteve French 	} else {
133338c8a9a5SSteve French 		struct dfs_info3_param *refs = NULL;
133438c8a9a5SSteve French 		int num_refs = 0;
133538c8a9a5SSteve French 
133638c8a9a5SSteve French 		/*
133738c8a9a5SSteve French 		 * XXX: we are not using dfs_cache_find() here because we might
13383ae872deSPaulo Alcantara 		 * end up filling all the DFS cache and thus potentially
133938c8a9a5SSteve French 		 * removing cached DFS targets that the client would eventually
134038c8a9a5SSteve French 		 * need during failover.
134138c8a9a5SSteve French 		 */
134238c8a9a5SSteve French 		ses = CIFS_DFS_ROOT_SES(ses);
134338c8a9a5SSteve French 		if (ses->server->ops->get_dfs_refer &&
134438c8a9a5SSteve French 		    !ses->server->ops->get_dfs_refer(xid, ses, ref_path, &refs,
134538c8a9a5SSteve French 						     &num_refs, cifs_sb->local_nls,
134638c8a9a5SSteve French 						     cifs_remap(cifs_sb)))
134738c8a9a5SSteve French 			*islink = refs[0].server_type == DFS_TYPE_LINK;
134838c8a9a5SSteve French 		free_dfs_info_array(refs, num_refs);
134938c8a9a5SSteve French 		kfree(ref_path);
135038c8a9a5SSteve French 	}
135138c8a9a5SSteve French 	return 0;
135238c8a9a5SSteve French }
135338c8a9a5SSteve French #endif
135438c8a9a5SSteve French 
cifs_wait_for_server_reconnect(struct TCP_Server_Info * server,bool retry)135538c8a9a5SSteve French int cifs_wait_for_server_reconnect(struct TCP_Server_Info *server, bool retry)
135638c8a9a5SSteve French {
135738c8a9a5SSteve French 	int timeout = 10;
135838c8a9a5SSteve French 	int rc;
135938c8a9a5SSteve French 
136038c8a9a5SSteve French 	spin_lock(&server->srv_lock);
136138c8a9a5SSteve French 	if (server->tcpStatus != CifsNeedReconnect) {
136238c8a9a5SSteve French 		spin_unlock(&server->srv_lock);
136338c8a9a5SSteve French 		return 0;
136438c8a9a5SSteve French 	}
136538c8a9a5SSteve French 	timeout *= server->nr_targets;
136638c8a9a5SSteve French 	spin_unlock(&server->srv_lock);
136738c8a9a5SSteve French 
136838c8a9a5SSteve French 	/*
136938c8a9a5SSteve French 	 * Give demultiplex thread up to 10 seconds to each target available for
137038c8a9a5SSteve French 	 * reconnect -- should be greater than cifs socket timeout which is 7
137138c8a9a5SSteve French 	 * seconds.
137238c8a9a5SSteve French 	 *
137338c8a9a5SSteve French 	 * On "soft" mounts we wait once. Hard mounts keep retrying until
137438c8a9a5SSteve French 	 * process is killed or server comes back on-line.
137538c8a9a5SSteve French 	 */
137638c8a9a5SSteve French 	do {
137738c8a9a5SSteve French 		rc = wait_event_interruptible_timeout(server->response_q,
137838c8a9a5SSteve French 						      (server->tcpStatus != CifsNeedReconnect),
137938c8a9a5SSteve French 						      timeout * HZ);
138038c8a9a5SSteve French 		if (rc < 0) {
138138c8a9a5SSteve French 			cifs_dbg(FYI, "%s: aborting reconnect due to received signal\n",
138238c8a9a5SSteve French 				 __func__);
138338c8a9a5SSteve French 			return -ERESTARTSYS;
138438c8a9a5SSteve French 		}
138538c8a9a5SSteve French 
138638c8a9a5SSteve French 		/* are we still trying to reconnect? */
138738c8a9a5SSteve French 		spin_lock(&server->srv_lock);
138838c8a9a5SSteve French 		if (server->tcpStatus != CifsNeedReconnect) {
138938c8a9a5SSteve French 			spin_unlock(&server->srv_lock);
139038c8a9a5SSteve French 			return 0;
139138c8a9a5SSteve French 		}
139238c8a9a5SSteve French 		spin_unlock(&server->srv_lock);
139338c8a9a5SSteve French 	} while (retry);
139438c8a9a5SSteve French 
139538c8a9a5SSteve French 	cifs_dbg(FYI, "%s: gave up waiting on reconnect\n", __func__);
139638c8a9a5SSteve French 	return -EHOSTDOWN;
139738c8a9a5SSteve French }
1398