xref: /openbmc/linux/fs/smb/client/smb1ops.c (revision abea3c9a)
138c8a9a5SSteve French // SPDX-License-Identifier: GPL-2.0-only
238c8a9a5SSteve French /*
338c8a9a5SSteve French  *  SMB1 (CIFS) version specific operations
438c8a9a5SSteve French  *
538c8a9a5SSteve French  *  Copyright (c) 2012, Jeff Layton <jlayton@redhat.com>
638c8a9a5SSteve French  */
738c8a9a5SSteve French 
838c8a9a5SSteve French #include <linux/pagemap.h>
938c8a9a5SSteve French #include <linux/vfs.h>
1038c8a9a5SSteve French #include <uapi/linux/magic.h>
1138c8a9a5SSteve French #include "cifsglob.h"
1238c8a9a5SSteve French #include "cifsproto.h"
1338c8a9a5SSteve French #include "cifs_debug.h"
1438c8a9a5SSteve French #include "cifspdu.h"
1538c8a9a5SSteve French #include "cifs_unicode.h"
1638c8a9a5SSteve French #include "fs_context.h"
1738c8a9a5SSteve French 
1838c8a9a5SSteve French /*
1938c8a9a5SSteve French  * An NT cancel request header looks just like the original request except:
2038c8a9a5SSteve French  *
2138c8a9a5SSteve French  * The Command is SMB_COM_NT_CANCEL
2238c8a9a5SSteve French  * The WordCount is zeroed out
2338c8a9a5SSteve French  * The ByteCount is zeroed out
2438c8a9a5SSteve French  *
2538c8a9a5SSteve French  * This function mangles an existing request buffer into a
2638c8a9a5SSteve French  * SMB_COM_NT_CANCEL request and then sends it.
2738c8a9a5SSteve French  */
2838c8a9a5SSteve French static int
send_nt_cancel(struct TCP_Server_Info * server,struct smb_rqst * rqst,struct mid_q_entry * mid)2938c8a9a5SSteve French send_nt_cancel(struct TCP_Server_Info *server, struct smb_rqst *rqst,
3038c8a9a5SSteve French 	       struct mid_q_entry *mid)
3138c8a9a5SSteve French {
3238c8a9a5SSteve French 	int rc = 0;
3338c8a9a5SSteve French 	struct smb_hdr *in_buf = (struct smb_hdr *)rqst->rq_iov[0].iov_base;
3438c8a9a5SSteve French 
3538c8a9a5SSteve French 	/* -4 for RFC1001 length and +2 for BCC field */
3638c8a9a5SSteve French 	in_buf->smb_buf_length = cpu_to_be32(sizeof(struct smb_hdr) - 4  + 2);
3738c8a9a5SSteve French 	in_buf->Command = SMB_COM_NT_CANCEL;
3838c8a9a5SSteve French 	in_buf->WordCount = 0;
3938c8a9a5SSteve French 	put_bcc(0, in_buf);
4038c8a9a5SSteve French 
4138c8a9a5SSteve French 	cifs_server_lock(server);
4238c8a9a5SSteve French 	rc = cifs_sign_smb(in_buf, server, &mid->sequence_number);
4338c8a9a5SSteve French 	if (rc) {
4438c8a9a5SSteve French 		cifs_server_unlock(server);
4538c8a9a5SSteve French 		return rc;
4638c8a9a5SSteve French 	}
4738c8a9a5SSteve French 
4838c8a9a5SSteve French 	/*
4938c8a9a5SSteve French 	 * The response to this call was already factored into the sequence
5038c8a9a5SSteve French 	 * number when the call went out, so we must adjust it back downward
5138c8a9a5SSteve French 	 * after signing here.
5238c8a9a5SSteve French 	 */
5338c8a9a5SSteve French 	--server->sequence_number;
5438c8a9a5SSteve French 	rc = smb_send(server, in_buf, be32_to_cpu(in_buf->smb_buf_length));
5538c8a9a5SSteve French 	if (rc < 0)
5638c8a9a5SSteve French 		server->sequence_number--;
5738c8a9a5SSteve French 
5838c8a9a5SSteve French 	cifs_server_unlock(server);
5938c8a9a5SSteve French 
6038c8a9a5SSteve French 	cifs_dbg(FYI, "issued NT_CANCEL for mid %u, rc = %d\n",
6138c8a9a5SSteve French 		 get_mid(in_buf), rc);
6238c8a9a5SSteve French 
6338c8a9a5SSteve French 	return rc;
6438c8a9a5SSteve French }
6538c8a9a5SSteve French 
6638c8a9a5SSteve French static bool
cifs_compare_fids(struct cifsFileInfo * ob1,struct cifsFileInfo * ob2)6738c8a9a5SSteve French cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
6838c8a9a5SSteve French {
6938c8a9a5SSteve French 	return ob1->fid.netfid == ob2->fid.netfid;
7038c8a9a5SSteve French }
7138c8a9a5SSteve French 
7238c8a9a5SSteve French static unsigned int
cifs_read_data_offset(char * buf)7338c8a9a5SSteve French cifs_read_data_offset(char *buf)
7438c8a9a5SSteve French {
7538c8a9a5SSteve French 	READ_RSP *rsp = (READ_RSP *)buf;
7638c8a9a5SSteve French 	return le16_to_cpu(rsp->DataOffset);
7738c8a9a5SSteve French }
7838c8a9a5SSteve French 
7938c8a9a5SSteve French static unsigned int
cifs_read_data_length(char * buf,bool in_remaining)8038c8a9a5SSteve French cifs_read_data_length(char *buf, bool in_remaining)
8138c8a9a5SSteve French {
8238c8a9a5SSteve French 	READ_RSP *rsp = (READ_RSP *)buf;
8338c8a9a5SSteve French 	/* It's a bug reading remaining data for SMB1 packets */
8438c8a9a5SSteve French 	WARN_ON(in_remaining);
8538c8a9a5SSteve French 	return (le16_to_cpu(rsp->DataLengthHigh) << 16) +
8638c8a9a5SSteve French 	       le16_to_cpu(rsp->DataLength);
8738c8a9a5SSteve French }
8838c8a9a5SSteve French 
8938c8a9a5SSteve French static struct mid_q_entry *
cifs_find_mid(struct TCP_Server_Info * server,char * buffer)9038c8a9a5SSteve French cifs_find_mid(struct TCP_Server_Info *server, char *buffer)
9138c8a9a5SSteve French {
9238c8a9a5SSteve French 	struct smb_hdr *buf = (struct smb_hdr *)buffer;
9338c8a9a5SSteve French 	struct mid_q_entry *mid;
9438c8a9a5SSteve French 
9538c8a9a5SSteve French 	spin_lock(&server->mid_lock);
9638c8a9a5SSteve French 	list_for_each_entry(mid, &server->pending_mid_q, qhead) {
9738c8a9a5SSteve French 		if (compare_mid(mid->mid, buf) &&
9838c8a9a5SSteve French 		    mid->mid_state == MID_REQUEST_SUBMITTED &&
9938c8a9a5SSteve French 		    le16_to_cpu(mid->command) == buf->Command) {
10038c8a9a5SSteve French 			kref_get(&mid->refcount);
10138c8a9a5SSteve French 			spin_unlock(&server->mid_lock);
10238c8a9a5SSteve French 			return mid;
10338c8a9a5SSteve French 		}
10438c8a9a5SSteve French 	}
10538c8a9a5SSteve French 	spin_unlock(&server->mid_lock);
10638c8a9a5SSteve French 	return NULL;
10738c8a9a5SSteve French }
10838c8a9a5SSteve French 
10938c8a9a5SSteve French static void
cifs_add_credits(struct TCP_Server_Info * server,const struct cifs_credits * credits,const int optype)11038c8a9a5SSteve French cifs_add_credits(struct TCP_Server_Info *server,
11138c8a9a5SSteve French 		 const struct cifs_credits *credits, const int optype)
11238c8a9a5SSteve French {
11338c8a9a5SSteve French 	spin_lock(&server->req_lock);
11438c8a9a5SSteve French 	server->credits += credits->value;
11538c8a9a5SSteve French 	server->in_flight--;
11638c8a9a5SSteve French 	spin_unlock(&server->req_lock);
11738c8a9a5SSteve French 	wake_up(&server->request_q);
11838c8a9a5SSteve French }
11938c8a9a5SSteve French 
12038c8a9a5SSteve French static void
cifs_set_credits(struct TCP_Server_Info * server,const int val)12138c8a9a5SSteve French cifs_set_credits(struct TCP_Server_Info *server, const int val)
12238c8a9a5SSteve French {
12338c8a9a5SSteve French 	spin_lock(&server->req_lock);
12438c8a9a5SSteve French 	server->credits = val;
12538c8a9a5SSteve French 	server->oplocks = val > 1 ? enable_oplocks : false;
12638c8a9a5SSteve French 	spin_unlock(&server->req_lock);
12738c8a9a5SSteve French }
12838c8a9a5SSteve French 
12938c8a9a5SSteve French static int *
cifs_get_credits_field(struct TCP_Server_Info * server,const int optype)13038c8a9a5SSteve French cifs_get_credits_field(struct TCP_Server_Info *server, const int optype)
13138c8a9a5SSteve French {
13238c8a9a5SSteve French 	return &server->credits;
13338c8a9a5SSteve French }
13438c8a9a5SSteve French 
13538c8a9a5SSteve French static unsigned int
cifs_get_credits(struct mid_q_entry * mid)13638c8a9a5SSteve French cifs_get_credits(struct mid_q_entry *mid)
13738c8a9a5SSteve French {
13838c8a9a5SSteve French 	return 1;
13938c8a9a5SSteve French }
14038c8a9a5SSteve French 
14138c8a9a5SSteve French /*
14238c8a9a5SSteve French  * Find a free multiplex id (SMB mid). Otherwise there could be
14338c8a9a5SSteve French  * mid collisions which might cause problems, demultiplexing the
14438c8a9a5SSteve French  * wrong response to this request. Multiplex ids could collide if
14538c8a9a5SSteve French  * one of a series requests takes much longer than the others, or
14638c8a9a5SSteve French  * if a very large number of long lived requests (byte range
14738c8a9a5SSteve French  * locks or FindNotify requests) are pending. No more than
14838c8a9a5SSteve French  * 64K-1 requests can be outstanding at one time. If no
14938c8a9a5SSteve French  * mids are available, return zero. A future optimization
15038c8a9a5SSteve French  * could make the combination of mids and uid the key we use
15138c8a9a5SSteve French  * to demultiplex on (rather than mid alone).
15238c8a9a5SSteve French  * In addition to the above check, the cifs demultiplex
15338c8a9a5SSteve French  * code already used the command code as a secondary
15438c8a9a5SSteve French  * check of the frame and if signing is negotiated the
15538c8a9a5SSteve French  * response would be discarded if the mid were the same
15638c8a9a5SSteve French  * but the signature was wrong. Since the mid is not put in the
15738c8a9a5SSteve French  * pending queue until later (when it is about to be dispatched)
15838c8a9a5SSteve French  * we do have to limit the number of outstanding requests
15938c8a9a5SSteve French  * to somewhat less than 64K-1 although it is hard to imagine
16038c8a9a5SSteve French  * so many threads being in the vfs at one time.
16138c8a9a5SSteve French  */
16238c8a9a5SSteve French static __u64
cifs_get_next_mid(struct TCP_Server_Info * server)16338c8a9a5SSteve French cifs_get_next_mid(struct TCP_Server_Info *server)
16438c8a9a5SSteve French {
16538c8a9a5SSteve French 	__u64 mid = 0;
16638c8a9a5SSteve French 	__u16 last_mid, cur_mid;
16738c8a9a5SSteve French 	bool collision, reconnect = false;
16838c8a9a5SSteve French 
16938c8a9a5SSteve French 	spin_lock(&server->mid_lock);
17038c8a9a5SSteve French 
17138c8a9a5SSteve French 	/* mid is 16 bit only for CIFS/SMB */
17238c8a9a5SSteve French 	cur_mid = (__u16)((server->CurrentMid) & 0xffff);
17338c8a9a5SSteve French 	/* we do not want to loop forever */
17438c8a9a5SSteve French 	last_mid = cur_mid;
17538c8a9a5SSteve French 	cur_mid++;
17638c8a9a5SSteve French 	/* avoid 0xFFFF MID */
17738c8a9a5SSteve French 	if (cur_mid == 0xffff)
17838c8a9a5SSteve French 		cur_mid++;
17938c8a9a5SSteve French 
18038c8a9a5SSteve French 	/*
18138c8a9a5SSteve French 	 * This nested loop looks more expensive than it is.
18238c8a9a5SSteve French 	 * In practice the list of pending requests is short,
18338c8a9a5SSteve French 	 * fewer than 50, and the mids are likely to be unique
18438c8a9a5SSteve French 	 * on the first pass through the loop unless some request
18538c8a9a5SSteve French 	 * takes longer than the 64 thousand requests before it
18638c8a9a5SSteve French 	 * (and it would also have to have been a request that
18738c8a9a5SSteve French 	 * did not time out).
18838c8a9a5SSteve French 	 */
18938c8a9a5SSteve French 	while (cur_mid != last_mid) {
19038c8a9a5SSteve French 		struct mid_q_entry *mid_entry;
19138c8a9a5SSteve French 		unsigned int num_mids;
19238c8a9a5SSteve French 
19338c8a9a5SSteve French 		collision = false;
19438c8a9a5SSteve French 		if (cur_mid == 0)
19538c8a9a5SSteve French 			cur_mid++;
19638c8a9a5SSteve French 
19738c8a9a5SSteve French 		num_mids = 0;
19838c8a9a5SSteve French 		list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) {
19938c8a9a5SSteve French 			++num_mids;
20038c8a9a5SSteve French 			if (mid_entry->mid == cur_mid &&
20138c8a9a5SSteve French 			    mid_entry->mid_state == MID_REQUEST_SUBMITTED) {
20238c8a9a5SSteve French 				/* This mid is in use, try a different one */
20338c8a9a5SSteve French 				collision = true;
20438c8a9a5SSteve French 				break;
20538c8a9a5SSteve French 			}
20638c8a9a5SSteve French 		}
20738c8a9a5SSteve French 
20838c8a9a5SSteve French 		/*
20938c8a9a5SSteve French 		 * if we have more than 32k mids in the list, then something
21038c8a9a5SSteve French 		 * is very wrong. Possibly a local user is trying to DoS the
21138c8a9a5SSteve French 		 * box by issuing long-running calls and SIGKILL'ing them. If
21238c8a9a5SSteve French 		 * we get to 2^16 mids then we're in big trouble as this
21338c8a9a5SSteve French 		 * function could loop forever.
21438c8a9a5SSteve French 		 *
21538c8a9a5SSteve French 		 * Go ahead and assign out the mid in this situation, but force
21638c8a9a5SSteve French 		 * an eventual reconnect to clean out the pending_mid_q.
21738c8a9a5SSteve French 		 */
21838c8a9a5SSteve French 		if (num_mids > 32768)
21938c8a9a5SSteve French 			reconnect = true;
22038c8a9a5SSteve French 
22138c8a9a5SSteve French 		if (!collision) {
22238c8a9a5SSteve French 			mid = (__u64)cur_mid;
22338c8a9a5SSteve French 			server->CurrentMid = mid;
22438c8a9a5SSteve French 			break;
22538c8a9a5SSteve French 		}
22638c8a9a5SSteve French 		cur_mid++;
22738c8a9a5SSteve French 	}
22838c8a9a5SSteve French 	spin_unlock(&server->mid_lock);
22938c8a9a5SSteve French 
23038c8a9a5SSteve French 	if (reconnect) {
23138c8a9a5SSteve French 		cifs_signal_cifsd_for_reconnect(server, false);
23238c8a9a5SSteve French 	}
23338c8a9a5SSteve French 
23438c8a9a5SSteve French 	return mid;
23538c8a9a5SSteve French }
23638c8a9a5SSteve French 
23738c8a9a5SSteve French /*
23838c8a9a5SSteve French 	return codes:
23938c8a9a5SSteve French 		0	not a transact2, or all data present
24038c8a9a5SSteve French 		>0	transact2 with that much data missing
24138c8a9a5SSteve French 		-EINVAL	invalid transact2
24238c8a9a5SSteve French  */
24338c8a9a5SSteve French static int
check2ndT2(char * buf)24438c8a9a5SSteve French check2ndT2(char *buf)
24538c8a9a5SSteve French {
24638c8a9a5SSteve French 	struct smb_hdr *pSMB = (struct smb_hdr *)buf;
24738c8a9a5SSteve French 	struct smb_t2_rsp *pSMBt;
24838c8a9a5SSteve French 	int remaining;
24938c8a9a5SSteve French 	__u16 total_data_size, data_in_this_rsp;
25038c8a9a5SSteve French 
25138c8a9a5SSteve French 	if (pSMB->Command != SMB_COM_TRANSACTION2)
25238c8a9a5SSteve French 		return 0;
25338c8a9a5SSteve French 
25438c8a9a5SSteve French 	/* check for plausible wct, bcc and t2 data and parm sizes */
25538c8a9a5SSteve French 	/* check for parm and data offset going beyond end of smb */
25638c8a9a5SSteve French 	if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
25738c8a9a5SSteve French 		cifs_dbg(FYI, "Invalid transact2 word count\n");
25838c8a9a5SSteve French 		return -EINVAL;
25938c8a9a5SSteve French 	}
26038c8a9a5SSteve French 
26138c8a9a5SSteve French 	pSMBt = (struct smb_t2_rsp *)pSMB;
26238c8a9a5SSteve French 
26338c8a9a5SSteve French 	total_data_size = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
26438c8a9a5SSteve French 	data_in_this_rsp = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
26538c8a9a5SSteve French 
26638c8a9a5SSteve French 	if (total_data_size == data_in_this_rsp)
26738c8a9a5SSteve French 		return 0;
26838c8a9a5SSteve French 	else if (total_data_size < data_in_this_rsp) {
26938c8a9a5SSteve French 		cifs_dbg(FYI, "total data %d smaller than data in frame %d\n",
27038c8a9a5SSteve French 			 total_data_size, data_in_this_rsp);
27138c8a9a5SSteve French 		return -EINVAL;
27238c8a9a5SSteve French 	}
27338c8a9a5SSteve French 
27438c8a9a5SSteve French 	remaining = total_data_size - data_in_this_rsp;
27538c8a9a5SSteve French 
27638c8a9a5SSteve French 	cifs_dbg(FYI, "missing %d bytes from transact2, check next response\n",
27738c8a9a5SSteve French 		 remaining);
27838c8a9a5SSteve French 	if (total_data_size > CIFSMaxBufSize) {
27938c8a9a5SSteve French 		cifs_dbg(VFS, "TotalDataSize %d is over maximum buffer %d\n",
28038c8a9a5SSteve French 			 total_data_size, CIFSMaxBufSize);
28138c8a9a5SSteve French 		return -EINVAL;
28238c8a9a5SSteve French 	}
28338c8a9a5SSteve French 	return remaining;
28438c8a9a5SSteve French }
28538c8a9a5SSteve French 
28638c8a9a5SSteve French static int
coalesce_t2(char * second_buf,struct smb_hdr * target_hdr)28738c8a9a5SSteve French coalesce_t2(char *second_buf, struct smb_hdr *target_hdr)
28838c8a9a5SSteve French {
28938c8a9a5SSteve French 	struct smb_t2_rsp *pSMBs = (struct smb_t2_rsp *)second_buf;
29038c8a9a5SSteve French 	struct smb_t2_rsp *pSMBt  = (struct smb_t2_rsp *)target_hdr;
29138c8a9a5SSteve French 	char *data_area_of_tgt;
29238c8a9a5SSteve French 	char *data_area_of_src;
29338c8a9a5SSteve French 	int remaining;
29438c8a9a5SSteve French 	unsigned int byte_count, total_in_tgt;
29538c8a9a5SSteve French 	__u16 tgt_total_cnt, src_total_cnt, total_in_src;
29638c8a9a5SSteve French 
29738c8a9a5SSteve French 	src_total_cnt = get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount);
29838c8a9a5SSteve French 	tgt_total_cnt = get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount);
29938c8a9a5SSteve French 
30038c8a9a5SSteve French 	if (tgt_total_cnt != src_total_cnt)
30138c8a9a5SSteve French 		cifs_dbg(FYI, "total data count of primary and secondary t2 differ source=%hu target=%hu\n",
30238c8a9a5SSteve French 			 src_total_cnt, tgt_total_cnt);
30338c8a9a5SSteve French 
30438c8a9a5SSteve French 	total_in_tgt = get_unaligned_le16(&pSMBt->t2_rsp.DataCount);
30538c8a9a5SSteve French 
30638c8a9a5SSteve French 	remaining = tgt_total_cnt - total_in_tgt;
30738c8a9a5SSteve French 
30838c8a9a5SSteve French 	if (remaining < 0) {
30938c8a9a5SSteve French 		cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%u\n",
31038c8a9a5SSteve French 			 tgt_total_cnt, total_in_tgt);
31138c8a9a5SSteve French 		return -EPROTO;
31238c8a9a5SSteve French 	}
31338c8a9a5SSteve French 
31438c8a9a5SSteve French 	if (remaining == 0) {
31538c8a9a5SSteve French 		/* nothing to do, ignore */
31638c8a9a5SSteve French 		cifs_dbg(FYI, "no more data remains\n");
31738c8a9a5SSteve French 		return 0;
31838c8a9a5SSteve French 	}
31938c8a9a5SSteve French 
32038c8a9a5SSteve French 	total_in_src = get_unaligned_le16(&pSMBs->t2_rsp.DataCount);
32138c8a9a5SSteve French 	if (remaining < total_in_src)
32238c8a9a5SSteve French 		cifs_dbg(FYI, "transact2 2nd response contains too much data\n");
32338c8a9a5SSteve French 
32438c8a9a5SSteve French 	/* find end of first SMB data area */
32538c8a9a5SSteve French 	data_area_of_tgt = (char *)&pSMBt->hdr.Protocol +
32638c8a9a5SSteve French 				get_unaligned_le16(&pSMBt->t2_rsp.DataOffset);
32738c8a9a5SSteve French 
32838c8a9a5SSteve French 	/* validate target area */
32938c8a9a5SSteve French 	data_area_of_src = (char *)&pSMBs->hdr.Protocol +
33038c8a9a5SSteve French 				get_unaligned_le16(&pSMBs->t2_rsp.DataOffset);
33138c8a9a5SSteve French 
33238c8a9a5SSteve French 	data_area_of_tgt += total_in_tgt;
33338c8a9a5SSteve French 
33438c8a9a5SSteve French 	total_in_tgt += total_in_src;
33538c8a9a5SSteve French 	/* is the result too big for the field? */
33638c8a9a5SSteve French 	if (total_in_tgt > USHRT_MAX) {
33738c8a9a5SSteve French 		cifs_dbg(FYI, "coalesced DataCount too large (%u)\n",
33838c8a9a5SSteve French 			 total_in_tgt);
33938c8a9a5SSteve French 		return -EPROTO;
34038c8a9a5SSteve French 	}
34138c8a9a5SSteve French 	put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount);
34238c8a9a5SSteve French 
34338c8a9a5SSteve French 	/* fix up the BCC */
34438c8a9a5SSteve French 	byte_count = get_bcc(target_hdr);
34538c8a9a5SSteve French 	byte_count += total_in_src;
34638c8a9a5SSteve French 	/* is the result too big for the field? */
34738c8a9a5SSteve French 	if (byte_count > USHRT_MAX) {
34838c8a9a5SSteve French 		cifs_dbg(FYI, "coalesced BCC too large (%u)\n", byte_count);
34938c8a9a5SSteve French 		return -EPROTO;
35038c8a9a5SSteve French 	}
35138c8a9a5SSteve French 	put_bcc(byte_count, target_hdr);
35238c8a9a5SSteve French 
35338c8a9a5SSteve French 	byte_count = be32_to_cpu(target_hdr->smb_buf_length);
35438c8a9a5SSteve French 	byte_count += total_in_src;
35538c8a9a5SSteve French 	/* don't allow buffer to overflow */
35638c8a9a5SSteve French 	if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
35738c8a9a5SSteve French 		cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n",
35838c8a9a5SSteve French 			 byte_count);
35938c8a9a5SSteve French 		return -ENOBUFS;
36038c8a9a5SSteve French 	}
36138c8a9a5SSteve French 	target_hdr->smb_buf_length = cpu_to_be32(byte_count);
36238c8a9a5SSteve French 
36338c8a9a5SSteve French 	/* copy second buffer into end of first buffer */
36438c8a9a5SSteve French 	memcpy(data_area_of_tgt, data_area_of_src, total_in_src);
36538c8a9a5SSteve French 
36638c8a9a5SSteve French 	if (remaining != total_in_src) {
36738c8a9a5SSteve French 		/* more responses to go */
36838c8a9a5SSteve French 		cifs_dbg(FYI, "waiting for more secondary responses\n");
36938c8a9a5SSteve French 		return 1;
37038c8a9a5SSteve French 	}
37138c8a9a5SSteve French 
37238c8a9a5SSteve French 	/* we are done */
37338c8a9a5SSteve French 	cifs_dbg(FYI, "found the last secondary response\n");
37438c8a9a5SSteve French 	return 0;
37538c8a9a5SSteve French }
37638c8a9a5SSteve French 
37738c8a9a5SSteve French static void
cifs_downgrade_oplock(struct TCP_Server_Info * server,struct cifsInodeInfo * cinode,__u32 oplock,unsigned int epoch,bool * purge_cache)37838c8a9a5SSteve French cifs_downgrade_oplock(struct TCP_Server_Info *server,
37938c8a9a5SSteve French 		      struct cifsInodeInfo *cinode, __u32 oplock,
38038c8a9a5SSteve French 		      unsigned int epoch, bool *purge_cache)
38138c8a9a5SSteve French {
38238c8a9a5SSteve French 	cifs_set_oplock_level(cinode, oplock);
38338c8a9a5SSteve French }
38438c8a9a5SSteve French 
38538c8a9a5SSteve French static bool
cifs_check_trans2(struct mid_q_entry * mid,struct TCP_Server_Info * server,char * buf,int malformed)38638c8a9a5SSteve French cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server,
38738c8a9a5SSteve French 		  char *buf, int malformed)
38838c8a9a5SSteve French {
38938c8a9a5SSteve French 	if (malformed)
39038c8a9a5SSteve French 		return false;
39138c8a9a5SSteve French 	if (check2ndT2(buf) <= 0)
39238c8a9a5SSteve French 		return false;
39338c8a9a5SSteve French 	mid->multiRsp = true;
39438c8a9a5SSteve French 	if (mid->resp_buf) {
39538c8a9a5SSteve French 		/* merge response - fix up 1st*/
39638c8a9a5SSteve French 		malformed = coalesce_t2(buf, mid->resp_buf);
39738c8a9a5SSteve French 		if (malformed > 0)
39838c8a9a5SSteve French 			return true;
39938c8a9a5SSteve French 		/* All parts received or packet is malformed. */
40038c8a9a5SSteve French 		mid->multiEnd = true;
40138c8a9a5SSteve French 		dequeue_mid(mid, malformed);
40238c8a9a5SSteve French 		return true;
40338c8a9a5SSteve French 	}
40438c8a9a5SSteve French 	if (!server->large_buf) {
40538c8a9a5SSteve French 		/*FIXME: switch to already allocated largebuf?*/
40638c8a9a5SSteve French 		cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n");
40738c8a9a5SSteve French 	} else {
40838c8a9a5SSteve French 		/* Have first buffer */
40938c8a9a5SSteve French 		mid->resp_buf = buf;
41038c8a9a5SSteve French 		mid->large_buf = true;
41138c8a9a5SSteve French 		server->bigbuf = NULL;
41238c8a9a5SSteve French 	}
41338c8a9a5SSteve French 	return true;
41438c8a9a5SSteve French }
41538c8a9a5SSteve French 
41638c8a9a5SSteve French static bool
cifs_need_neg(struct TCP_Server_Info * server)41738c8a9a5SSteve French cifs_need_neg(struct TCP_Server_Info *server)
41838c8a9a5SSteve French {
41938c8a9a5SSteve French 	return server->maxBuf == 0;
42038c8a9a5SSteve French }
42138c8a9a5SSteve French 
42238c8a9a5SSteve French static int
cifs_negotiate(const unsigned int xid,struct cifs_ses * ses,struct TCP_Server_Info * server)42338c8a9a5SSteve French cifs_negotiate(const unsigned int xid,
42438c8a9a5SSteve French 	       struct cifs_ses *ses,
42538c8a9a5SSteve French 	       struct TCP_Server_Info *server)
42638c8a9a5SSteve French {
42738c8a9a5SSteve French 	int rc;
42838c8a9a5SSteve French 	rc = CIFSSMBNegotiate(xid, ses, server);
42938c8a9a5SSteve French 	if (rc == -EAGAIN) {
43038c8a9a5SSteve French 		/* retry only once on 1st time connection */
43138c8a9a5SSteve French 		set_credits(server, 1);
43238c8a9a5SSteve French 		rc = CIFSSMBNegotiate(xid, ses, server);
43338c8a9a5SSteve French 		if (rc == -EAGAIN)
43438c8a9a5SSteve French 			rc = -EHOSTDOWN;
43538c8a9a5SSteve French 	}
43638c8a9a5SSteve French 	return rc;
43738c8a9a5SSteve French }
43838c8a9a5SSteve French 
43938c8a9a5SSteve French static unsigned int
cifs_negotiate_wsize(struct cifs_tcon * tcon,struct smb3_fs_context * ctx)44038c8a9a5SSteve French cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
44138c8a9a5SSteve French {
44238c8a9a5SSteve French 	__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
44338c8a9a5SSteve French 	struct TCP_Server_Info *server = tcon->ses->server;
44438c8a9a5SSteve French 	unsigned int wsize;
44538c8a9a5SSteve French 
44638c8a9a5SSteve French 	/* start with specified wsize, or default */
44738c8a9a5SSteve French 	if (ctx->wsize)
44838c8a9a5SSteve French 		wsize = ctx->wsize;
44938c8a9a5SSteve French 	else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
45038c8a9a5SSteve French 		wsize = CIFS_DEFAULT_IOSIZE;
45138c8a9a5SSteve French 	else
45238c8a9a5SSteve French 		wsize = CIFS_DEFAULT_NON_POSIX_WSIZE;
45338c8a9a5SSteve French 
45438c8a9a5SSteve French 	/* can server support 24-bit write sizes? (via UNIX extensions) */
45538c8a9a5SSteve French 	if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
45638c8a9a5SSteve French 		wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE);
45738c8a9a5SSteve French 
45838c8a9a5SSteve French 	/*
45938c8a9a5SSteve French 	 * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set?
46038c8a9a5SSteve French 	 * Limit it to max buffer offered by the server, minus the size of the
46138c8a9a5SSteve French 	 * WRITEX header, not including the 4 byte RFC1001 length.
46238c8a9a5SSteve French 	 */
46338c8a9a5SSteve French 	if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
46438c8a9a5SSteve French 	    (!(server->capabilities & CAP_UNIX) && server->sign))
46538c8a9a5SSteve French 		wsize = min_t(unsigned int, wsize,
46638c8a9a5SSteve French 				server->maxBuf - sizeof(WRITE_REQ) + 4);
46738c8a9a5SSteve French 
46838c8a9a5SSteve French 	/* hard limit of CIFS_MAX_WSIZE */
46938c8a9a5SSteve French 	wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
47038c8a9a5SSteve French 
47138c8a9a5SSteve French 	return wsize;
47238c8a9a5SSteve French }
47338c8a9a5SSteve French 
47438c8a9a5SSteve French static unsigned int
cifs_negotiate_rsize(struct cifs_tcon * tcon,struct smb3_fs_context * ctx)47538c8a9a5SSteve French cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
47638c8a9a5SSteve French {
47738c8a9a5SSteve French 	__u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
47838c8a9a5SSteve French 	struct TCP_Server_Info *server = tcon->ses->server;
47938c8a9a5SSteve French 	unsigned int rsize, defsize;
48038c8a9a5SSteve French 
48138c8a9a5SSteve French 	/*
48238c8a9a5SSteve French 	 * Set default value...
48338c8a9a5SSteve French 	 *
48438c8a9a5SSteve French 	 * HACK alert! Ancient servers have very small buffers. Even though
48538c8a9a5SSteve French 	 * MS-CIFS indicates that servers are only limited by the client's
48638c8a9a5SSteve French 	 * bufsize for reads, testing against win98se shows that it throws
48738c8a9a5SSteve French 	 * INVALID_PARAMETER errors if you try to request too large a read.
48838c8a9a5SSteve French 	 * OS/2 just sends back short reads.
48938c8a9a5SSteve French 	 *
49038c8a9a5SSteve French 	 * If the server doesn't advertise CAP_LARGE_READ_X, then assume that
49138c8a9a5SSteve French 	 * it can't handle a read request larger than its MaxBufferSize either.
49238c8a9a5SSteve French 	 */
49338c8a9a5SSteve French 	if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
49438c8a9a5SSteve French 		defsize = CIFS_DEFAULT_IOSIZE;
49538c8a9a5SSteve French 	else if (server->capabilities & CAP_LARGE_READ_X)
49638c8a9a5SSteve French 		defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
49738c8a9a5SSteve French 	else
49838c8a9a5SSteve French 		defsize = server->maxBuf - sizeof(READ_RSP);
49938c8a9a5SSteve French 
50038c8a9a5SSteve French 	rsize = ctx->rsize ? ctx->rsize : defsize;
50138c8a9a5SSteve French 
50238c8a9a5SSteve French 	/*
50338c8a9a5SSteve French 	 * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
50438c8a9a5SSteve French 	 * the client's MaxBufferSize.
50538c8a9a5SSteve French 	 */
50638c8a9a5SSteve French 	if (!(server->capabilities & CAP_LARGE_READ_X))
50738c8a9a5SSteve French 		rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
50838c8a9a5SSteve French 
50938c8a9a5SSteve French 	/* hard limit of CIFS_MAX_RSIZE */
51038c8a9a5SSteve French 	rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
51138c8a9a5SSteve French 
51238c8a9a5SSteve French 	return rsize;
51338c8a9a5SSteve French }
51438c8a9a5SSteve French 
51538c8a9a5SSteve French static void
cifs_qfs_tcon(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb)51638c8a9a5SSteve French cifs_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon,
51738c8a9a5SSteve French 	      struct cifs_sb_info *cifs_sb)
51838c8a9a5SSteve French {
51938c8a9a5SSteve French 	CIFSSMBQFSDeviceInfo(xid, tcon);
52038c8a9a5SSteve French 	CIFSSMBQFSAttributeInfo(xid, tcon);
52138c8a9a5SSteve French }
52238c8a9a5SSteve French 
52338c8a9a5SSteve French static int
cifs_is_path_accessible(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path)52438c8a9a5SSteve French cifs_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
52538c8a9a5SSteve French 			struct cifs_sb_info *cifs_sb, const char *full_path)
52638c8a9a5SSteve French {
52738c8a9a5SSteve French 	int rc;
52838c8a9a5SSteve French 	FILE_ALL_INFO *file_info;
52938c8a9a5SSteve French 
53038c8a9a5SSteve French 	file_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
53138c8a9a5SSteve French 	if (file_info == NULL)
53238c8a9a5SSteve French 		return -ENOMEM;
53338c8a9a5SSteve French 
53438c8a9a5SSteve French 	rc = CIFSSMBQPathInfo(xid, tcon, full_path, file_info,
53538c8a9a5SSteve French 			      0 /* not legacy */, cifs_sb->local_nls,
53638c8a9a5SSteve French 			      cifs_remap(cifs_sb));
53738c8a9a5SSteve French 
53838c8a9a5SSteve French 	if (rc == -EOPNOTSUPP || rc == -EINVAL)
53938c8a9a5SSteve French 		rc = SMBQueryInformation(xid, tcon, full_path, file_info,
54038c8a9a5SSteve French 				cifs_sb->local_nls, cifs_remap(cifs_sb));
54138c8a9a5SSteve French 	kfree(file_info);
54238c8a9a5SSteve French 	return rc;
54338c8a9a5SSteve French }
54438c8a9a5SSteve French 
cifs_query_path_info(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,struct cifs_open_info_data * data)5458b4e285dSPaulo Alcantara static int cifs_query_path_info(const unsigned int xid,
5468b4e285dSPaulo Alcantara 				struct cifs_tcon *tcon,
5478b4e285dSPaulo Alcantara 				struct cifs_sb_info *cifs_sb,
5488b4e285dSPaulo Alcantara 				const char *full_path,
5498b4e285dSPaulo Alcantara 				struct cifs_open_info_data *data)
55038c8a9a5SSteve French {
55138c8a9a5SSteve French 	int rc;
55238c8a9a5SSteve French 	FILE_ALL_INFO fi = {};
55338c8a9a5SSteve French 
5548b4e285dSPaulo Alcantara 	data->symlink = false;
5558b4e285dSPaulo Alcantara 	data->adjust_tz = false;
55638c8a9a5SSteve French 
55738c8a9a5SSteve French 	/* could do find first instead but this returns more info */
55838c8a9a5SSteve French 	rc = CIFSSMBQPathInfo(xid, tcon, full_path, &fi, 0 /* not legacy */, cifs_sb->local_nls,
55938c8a9a5SSteve French 			      cifs_remap(cifs_sb));
56038c8a9a5SSteve French 	/*
56138c8a9a5SSteve French 	 * BB optimize code so we do not make the above call when server claims
56238c8a9a5SSteve French 	 * no NT SMB support and the above call failed at least once - set flag
56338c8a9a5SSteve French 	 * in tcon or mount.
56438c8a9a5SSteve French 	 */
56538c8a9a5SSteve French 	if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
56638c8a9a5SSteve French 		rc = SMBQueryInformation(xid, tcon, full_path, &fi, cifs_sb->local_nls,
56738c8a9a5SSteve French 					 cifs_remap(cifs_sb));
5688b4e285dSPaulo Alcantara 		data->adjust_tz = true;
56938c8a9a5SSteve French 	}
57038c8a9a5SSteve French 
57138c8a9a5SSteve French 	if (!rc) {
57238c8a9a5SSteve French 		int tmprc;
57338c8a9a5SSteve French 		int oplock = 0;
57438c8a9a5SSteve French 		struct cifs_fid fid;
57538c8a9a5SSteve French 		struct cifs_open_parms oparms;
57638c8a9a5SSteve French 
57738c8a9a5SSteve French 		move_cifs_info_to_smb2(&data->fi, &fi);
57838c8a9a5SSteve French 
57938c8a9a5SSteve French 		if (!(le32_to_cpu(fi.Attributes) & ATTR_REPARSE))
58038c8a9a5SSteve French 			return 0;
58138c8a9a5SSteve French 
58238c8a9a5SSteve French 		oparms = (struct cifs_open_parms) {
58338c8a9a5SSteve French 			.tcon = tcon,
58438c8a9a5SSteve French 			.cifs_sb = cifs_sb,
58538c8a9a5SSteve French 			.desired_access = FILE_READ_ATTRIBUTES,
58638c8a9a5SSteve French 			.create_options = cifs_create_options(cifs_sb, 0),
58738c8a9a5SSteve French 			.disposition = FILE_OPEN,
58838c8a9a5SSteve French 			.path = full_path,
58938c8a9a5SSteve French 			.fid = &fid,
59038c8a9a5SSteve French 		};
59138c8a9a5SSteve French 
59238c8a9a5SSteve French 		/* Need to check if this is a symbolic link or not */
59338c8a9a5SSteve French 		tmprc = CIFS_open(xid, &oparms, &oplock, NULL);
59438c8a9a5SSteve French 		if (tmprc == -EOPNOTSUPP)
5958b4e285dSPaulo Alcantara 			data->symlink = true;
59638c8a9a5SSteve French 		else if (tmprc == 0)
59738c8a9a5SSteve French 			CIFSSMBClose(xid, tcon, fid.netfid);
59838c8a9a5SSteve French 	}
59938c8a9a5SSteve French 
60038c8a9a5SSteve French 	return rc;
60138c8a9a5SSteve French }
60238c8a9a5SSteve French 
cifs_get_srv_inum(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,u64 * uniqueid,struct cifs_open_info_data * unused)60338c8a9a5SSteve French static int cifs_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
60438c8a9a5SSteve French 			     struct cifs_sb_info *cifs_sb, const char *full_path,
60538c8a9a5SSteve French 			     u64 *uniqueid, struct cifs_open_info_data *unused)
60638c8a9a5SSteve French {
60738c8a9a5SSteve French 	/*
60838c8a9a5SSteve French 	 * We can not use the IndexNumber field by default from Windows or
60938c8a9a5SSteve French 	 * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA
61038c8a9a5SSteve French 	 * CIFS spec claims that this value is unique within the scope of a
61138c8a9a5SSteve French 	 * share, and the windows docs hint that it's actually unique
61238c8a9a5SSteve French 	 * per-machine.
61338c8a9a5SSteve French 	 *
61438c8a9a5SSteve French 	 * There may be higher info levels that work but are there Windows
61538c8a9a5SSteve French 	 * server or network appliances for which IndexNumber field is not
61638c8a9a5SSteve French 	 * guaranteed unique?
61738c8a9a5SSteve French 	 */
61838c8a9a5SSteve French 	return CIFSGetSrvInodeNumber(xid, tcon, full_path, uniqueid,
61938c8a9a5SSteve French 				     cifs_sb->local_nls,
62038c8a9a5SSteve French 				     cifs_remap(cifs_sb));
62138c8a9a5SSteve French }
62238c8a9a5SSteve French 
cifs_query_file_info(const unsigned int xid,struct cifs_tcon * tcon,struct cifsFileInfo * cfile,struct cifs_open_info_data * data)62338c8a9a5SSteve French static int cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
62438c8a9a5SSteve French 				struct cifsFileInfo *cfile, struct cifs_open_info_data *data)
62538c8a9a5SSteve French {
62638c8a9a5SSteve French 	int rc;
62738c8a9a5SSteve French 	FILE_ALL_INFO fi = {};
62838c8a9a5SSteve French 
62938c8a9a5SSteve French 	if (cfile->symlink_target) {
63038c8a9a5SSteve French 		data->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
63138c8a9a5SSteve French 		if (!data->symlink_target)
63238c8a9a5SSteve French 			return -ENOMEM;
63338c8a9a5SSteve French 	}
63438c8a9a5SSteve French 
63538c8a9a5SSteve French 	rc = CIFSSMBQFileInfo(xid, tcon, cfile->fid.netfid, &fi);
63638c8a9a5SSteve French 	if (!rc)
63738c8a9a5SSteve French 		move_cifs_info_to_smb2(&data->fi, &fi);
63838c8a9a5SSteve French 	return rc;
63938c8a9a5SSteve French }
64038c8a9a5SSteve French 
64138c8a9a5SSteve French static void
cifs_clear_stats(struct cifs_tcon * tcon)64238c8a9a5SSteve French cifs_clear_stats(struct cifs_tcon *tcon)
64338c8a9a5SSteve French {
64438c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_writes, 0);
64538c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_reads, 0);
64638c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_flushes, 0);
64738c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_oplock_brks, 0);
64838c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_opens, 0);
64938c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_posixopens, 0);
65038c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_posixmkdirs, 0);
65138c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_closes, 0);
65238c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_deletes, 0);
65338c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_mkdirs, 0);
65438c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_rmdirs, 0);
65538c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_renames, 0);
65638c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_t2renames, 0);
65738c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_ffirst, 0);
65838c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_fnext, 0);
65938c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_fclose, 0);
66038c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_hardlinks, 0);
66138c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_symlinks, 0);
66238c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_locks, 0);
66338c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_acl_get, 0);
66438c8a9a5SSteve French 	atomic_set(&tcon->stats.cifs_stats.num_acl_set, 0);
66538c8a9a5SSteve French }
66638c8a9a5SSteve French 
66738c8a9a5SSteve French static void
cifs_print_stats(struct seq_file * m,struct cifs_tcon * tcon)66838c8a9a5SSteve French cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
66938c8a9a5SSteve French {
67038c8a9a5SSteve French 	seq_printf(m, " Oplocks breaks: %d",
67138c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_oplock_brks));
67238c8a9a5SSteve French 	seq_printf(m, "\nReads:  %d Bytes: %llu",
67338c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_reads),
67438c8a9a5SSteve French 		   (long long)(tcon->bytes_read));
67538c8a9a5SSteve French 	seq_printf(m, "\nWrites: %d Bytes: %llu",
67638c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_writes),
67738c8a9a5SSteve French 		   (long long)(tcon->bytes_written));
67838c8a9a5SSteve French 	seq_printf(m, "\nFlushes: %d",
67938c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_flushes));
68038c8a9a5SSteve French 	seq_printf(m, "\nLocks: %d HardLinks: %d Symlinks: %d",
68138c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_locks),
68238c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_hardlinks),
68338c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_symlinks));
68438c8a9a5SSteve French 	seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d",
68538c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_opens),
68638c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_closes),
68738c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_deletes));
68838c8a9a5SSteve French 	seq_printf(m, "\nPosix Opens: %d Posix Mkdirs: %d",
68938c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_posixopens),
69038c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_posixmkdirs));
69138c8a9a5SSteve French 	seq_printf(m, "\nMkdirs: %d Rmdirs: %d",
69238c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_mkdirs),
69338c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_rmdirs));
69438c8a9a5SSteve French 	seq_printf(m, "\nRenames: %d T2 Renames %d",
69538c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_renames),
69638c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_t2renames));
69738c8a9a5SSteve French 	seq_printf(m, "\nFindFirst: %d FNext %d FClose %d",
69838c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_ffirst),
69938c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_fnext),
70038c8a9a5SSteve French 		   atomic_read(&tcon->stats.cifs_stats.num_fclose));
70138c8a9a5SSteve French }
70238c8a9a5SSteve French 
70338c8a9a5SSteve French static void
cifs_mkdir_setinfo(struct inode * inode,const char * full_path,struct cifs_sb_info * cifs_sb,struct cifs_tcon * tcon,const unsigned int xid)70438c8a9a5SSteve French cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
70538c8a9a5SSteve French 		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
70638c8a9a5SSteve French 		   const unsigned int xid)
70738c8a9a5SSteve French {
70838c8a9a5SSteve French 	FILE_BASIC_INFO info;
70938c8a9a5SSteve French 	struct cifsInodeInfo *cifsInode;
71038c8a9a5SSteve French 	u32 dosattrs;
71138c8a9a5SSteve French 	int rc;
71238c8a9a5SSteve French 
71338c8a9a5SSteve French 	memset(&info, 0, sizeof(info));
71438c8a9a5SSteve French 	cifsInode = CIFS_I(inode);
71538c8a9a5SSteve French 	dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
71638c8a9a5SSteve French 	info.Attributes = cpu_to_le32(dosattrs);
71738c8a9a5SSteve French 	rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls,
71838c8a9a5SSteve French 				cifs_sb);
71938c8a9a5SSteve French 	if (rc == 0)
72038c8a9a5SSteve French 		cifsInode->cifsAttrs = dosattrs;
72138c8a9a5SSteve French }
72238c8a9a5SSteve French 
cifs_open_file(const unsigned int xid,struct cifs_open_parms * oparms,__u32 * oplock,void * buf)72338c8a9a5SSteve French static int cifs_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
72438c8a9a5SSteve French 			  void *buf)
72538c8a9a5SSteve French {
72638c8a9a5SSteve French 	struct cifs_open_info_data *data = buf;
72738c8a9a5SSteve French 	FILE_ALL_INFO fi = {};
72838c8a9a5SSteve French 	int rc;
72938c8a9a5SSteve French 
73038c8a9a5SSteve French 	if (!(oparms->tcon->ses->capabilities & CAP_NT_SMBS))
73138c8a9a5SSteve French 		rc = SMBLegacyOpen(xid, oparms->tcon, oparms->path,
73238c8a9a5SSteve French 				   oparms->disposition,
73338c8a9a5SSteve French 				   oparms->desired_access,
73438c8a9a5SSteve French 				   oparms->create_options,
73538c8a9a5SSteve French 				   &oparms->fid->netfid, oplock, &fi,
73638c8a9a5SSteve French 				   oparms->cifs_sb->local_nls,
73738c8a9a5SSteve French 				   cifs_remap(oparms->cifs_sb));
73838c8a9a5SSteve French 	else
73938c8a9a5SSteve French 		rc = CIFS_open(xid, oparms, oplock, &fi);
74038c8a9a5SSteve French 
74138c8a9a5SSteve French 	if (!rc && data)
74238c8a9a5SSteve French 		move_cifs_info_to_smb2(&data->fi, &fi);
74338c8a9a5SSteve French 
74438c8a9a5SSteve French 	return rc;
74538c8a9a5SSteve French }
74638c8a9a5SSteve French 
74738c8a9a5SSteve French static void
cifs_set_fid(struct cifsFileInfo * cfile,struct cifs_fid * fid,__u32 oplock)74838c8a9a5SSteve French cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
74938c8a9a5SSteve French {
75038c8a9a5SSteve French 	struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
75138c8a9a5SSteve French 	cfile->fid.netfid = fid->netfid;
75238c8a9a5SSteve French 	cifs_set_oplock_level(cinode, oplock);
75338c8a9a5SSteve French 	cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode);
75438c8a9a5SSteve French }
75538c8a9a5SSteve French 
7566f17163bSRitvik Budhiraja static int
cifs_close_file(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_fid * fid)75738c8a9a5SSteve French cifs_close_file(const unsigned int xid, struct cifs_tcon *tcon,
75838c8a9a5SSteve French 		struct cifs_fid *fid)
75938c8a9a5SSteve French {
7606f17163bSRitvik Budhiraja 	return CIFSSMBClose(xid, tcon, fid->netfid);
76138c8a9a5SSteve French }
76238c8a9a5SSteve French 
76338c8a9a5SSteve French static int
cifs_flush_file(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_fid * fid)76438c8a9a5SSteve French cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
76538c8a9a5SSteve French 		struct cifs_fid *fid)
76638c8a9a5SSteve French {
76738c8a9a5SSteve French 	return CIFSSMBFlush(xid, tcon, fid->netfid);
76838c8a9a5SSteve French }
76938c8a9a5SSteve French 
77038c8a9a5SSteve French static int
cifs_sync_read(const unsigned int xid,struct cifs_fid * pfid,struct cifs_io_parms * parms,unsigned int * bytes_read,char ** buf,int * buf_type)77138c8a9a5SSteve French cifs_sync_read(const unsigned int xid, struct cifs_fid *pfid,
77238c8a9a5SSteve French 	       struct cifs_io_parms *parms, unsigned int *bytes_read,
77338c8a9a5SSteve French 	       char **buf, int *buf_type)
77438c8a9a5SSteve French {
77538c8a9a5SSteve French 	parms->netfid = pfid->netfid;
77638c8a9a5SSteve French 	return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type);
77738c8a9a5SSteve French }
77838c8a9a5SSteve French 
77938c8a9a5SSteve French static int
cifs_sync_write(const unsigned int xid,struct cifs_fid * pfid,struct cifs_io_parms * parms,unsigned int * written,struct kvec * iov,unsigned long nr_segs)78038c8a9a5SSteve French cifs_sync_write(const unsigned int xid, struct cifs_fid *pfid,
78138c8a9a5SSteve French 		struct cifs_io_parms *parms, unsigned int *written,
78238c8a9a5SSteve French 		struct kvec *iov, unsigned long nr_segs)
78338c8a9a5SSteve French {
78438c8a9a5SSteve French 
78538c8a9a5SSteve French 	parms->netfid = pfid->netfid;
78638c8a9a5SSteve French 	return CIFSSMBWrite2(xid, parms, written, iov, nr_segs);
78738c8a9a5SSteve French }
78838c8a9a5SSteve French 
78938c8a9a5SSteve French static int
smb_set_file_info(struct inode * inode,const char * full_path,FILE_BASIC_INFO * buf,const unsigned int xid)79038c8a9a5SSteve French smb_set_file_info(struct inode *inode, const char *full_path,
79138c8a9a5SSteve French 		  FILE_BASIC_INFO *buf, const unsigned int xid)
79238c8a9a5SSteve French {
79338c8a9a5SSteve French 	int oplock = 0;
79438c8a9a5SSteve French 	int rc;
79538c8a9a5SSteve French 	__u32 netpid;
79638c8a9a5SSteve French 	struct cifs_fid fid;
79738c8a9a5SSteve French 	struct cifs_open_parms oparms;
79838c8a9a5SSteve French 	struct cifsFileInfo *open_file;
79938c8a9a5SSteve French 	struct cifsInodeInfo *cinode = CIFS_I(inode);
80038c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
80138c8a9a5SSteve French 	struct tcon_link *tlink = NULL;
80238c8a9a5SSteve French 	struct cifs_tcon *tcon;
80338c8a9a5SSteve French 
80438c8a9a5SSteve French 	/* if the file is already open for write, just use that fileid */
80538c8a9a5SSteve French 	open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY);
80638c8a9a5SSteve French 	if (open_file) {
80738c8a9a5SSteve French 		fid.netfid = open_file->fid.netfid;
80838c8a9a5SSteve French 		netpid = open_file->pid;
80938c8a9a5SSteve French 		tcon = tlink_tcon(open_file->tlink);
81038c8a9a5SSteve French 		goto set_via_filehandle;
81138c8a9a5SSteve French 	}
81238c8a9a5SSteve French 
81338c8a9a5SSteve French 	tlink = cifs_sb_tlink(cifs_sb);
81438c8a9a5SSteve French 	if (IS_ERR(tlink)) {
81538c8a9a5SSteve French 		rc = PTR_ERR(tlink);
81638c8a9a5SSteve French 		tlink = NULL;
81738c8a9a5SSteve French 		goto out;
81838c8a9a5SSteve French 	}
81938c8a9a5SSteve French 	tcon = tlink_tcon(tlink);
82038c8a9a5SSteve French 
82138c8a9a5SSteve French 	rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls,
82238c8a9a5SSteve French 				cifs_sb);
82338c8a9a5SSteve French 	if (rc == 0) {
82438c8a9a5SSteve French 		cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
82538c8a9a5SSteve French 		goto out;
82638c8a9a5SSteve French 	} else if (rc != -EOPNOTSUPP && rc != -EINVAL) {
82738c8a9a5SSteve French 		goto out;
82838c8a9a5SSteve French 	}
82938c8a9a5SSteve French 
83038c8a9a5SSteve French 	oparms = (struct cifs_open_parms) {
83138c8a9a5SSteve French 		.tcon = tcon,
83238c8a9a5SSteve French 		.cifs_sb = cifs_sb,
83338c8a9a5SSteve French 		.desired_access = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
83438c8a9a5SSteve French 		.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
83538c8a9a5SSteve French 		.disposition = FILE_OPEN,
83638c8a9a5SSteve French 		.path = full_path,
83738c8a9a5SSteve French 		.fid = &fid,
83838c8a9a5SSteve French 	};
83938c8a9a5SSteve French 
84038c8a9a5SSteve French 	cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n");
84138c8a9a5SSteve French 	rc = CIFS_open(xid, &oparms, &oplock, NULL);
84238c8a9a5SSteve French 	if (rc != 0) {
84338c8a9a5SSteve French 		if (rc == -EIO)
84438c8a9a5SSteve French 			rc = -EINVAL;
84538c8a9a5SSteve French 		goto out;
84638c8a9a5SSteve French 	}
84738c8a9a5SSteve French 
84838c8a9a5SSteve French 	netpid = current->tgid;
84938c8a9a5SSteve French 
85038c8a9a5SSteve French set_via_filehandle:
85138c8a9a5SSteve French 	rc = CIFSSMBSetFileInfo(xid, tcon, buf, fid.netfid, netpid);
85238c8a9a5SSteve French 	if (!rc)
85338c8a9a5SSteve French 		cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
85438c8a9a5SSteve French 
85538c8a9a5SSteve French 	if (open_file == NULL)
85638c8a9a5SSteve French 		CIFSSMBClose(xid, tcon, fid.netfid);
85738c8a9a5SSteve French 	else
85838c8a9a5SSteve French 		cifsFileInfo_put(open_file);
85938c8a9a5SSteve French out:
86038c8a9a5SSteve French 	if (tlink != NULL)
86138c8a9a5SSteve French 		cifs_put_tlink(tlink);
86238c8a9a5SSteve French 	return rc;
86338c8a9a5SSteve French }
86438c8a9a5SSteve French 
86538c8a9a5SSteve French static int
cifs_set_compression(const unsigned int xid,struct cifs_tcon * tcon,struct cifsFileInfo * cfile)86638c8a9a5SSteve French cifs_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
86738c8a9a5SSteve French 		   struct cifsFileInfo *cfile)
86838c8a9a5SSteve French {
86938c8a9a5SSteve French 	return CIFSSMB_set_compression(xid, tcon, cfile->fid.netfid);
87038c8a9a5SSteve French }
87138c8a9a5SSteve French 
87238c8a9a5SSteve French static int
cifs_query_dir_first(const unsigned int xid,struct cifs_tcon * tcon,const char * path,struct cifs_sb_info * cifs_sb,struct cifs_fid * fid,__u16 search_flags,struct cifs_search_info * srch_inf)87338c8a9a5SSteve French cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
87438c8a9a5SSteve French 		     const char *path, struct cifs_sb_info *cifs_sb,
87538c8a9a5SSteve French 		     struct cifs_fid *fid, __u16 search_flags,
87638c8a9a5SSteve French 		     struct cifs_search_info *srch_inf)
87738c8a9a5SSteve French {
87838c8a9a5SSteve French 	int rc;
87938c8a9a5SSteve French 
88038c8a9a5SSteve French 	rc = CIFSFindFirst(xid, tcon, path, cifs_sb,
88138c8a9a5SSteve French 			   &fid->netfid, search_flags, srch_inf, true);
88238c8a9a5SSteve French 	if (rc)
88338c8a9a5SSteve French 		cifs_dbg(FYI, "find first failed=%d\n", rc);
88438c8a9a5SSteve French 	return rc;
88538c8a9a5SSteve French }
88638c8a9a5SSteve French 
88738c8a9a5SSteve French static int
cifs_query_dir_next(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_fid * fid,__u16 search_flags,struct cifs_search_info * srch_inf)88838c8a9a5SSteve French cifs_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon,
88938c8a9a5SSteve French 		    struct cifs_fid *fid, __u16 search_flags,
89038c8a9a5SSteve French 		    struct cifs_search_info *srch_inf)
89138c8a9a5SSteve French {
89238c8a9a5SSteve French 	return CIFSFindNext(xid, tcon, fid->netfid, search_flags, srch_inf);
89338c8a9a5SSteve French }
89438c8a9a5SSteve French 
89538c8a9a5SSteve French static int
cifs_close_dir(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_fid * fid)89638c8a9a5SSteve French cifs_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
89738c8a9a5SSteve French 	       struct cifs_fid *fid)
89838c8a9a5SSteve French {
89938c8a9a5SSteve French 	return CIFSFindClose(xid, tcon, fid->netfid);
90038c8a9a5SSteve French }
90138c8a9a5SSteve French 
90238c8a9a5SSteve French static int
cifs_oplock_response(struct cifs_tcon * tcon,__u64 persistent_fid,__u64 volatile_fid,__u16 net_fid,struct cifsInodeInfo * cinode)90338c8a9a5SSteve French cifs_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid,
90438c8a9a5SSteve French 		__u64 volatile_fid, __u16 net_fid, struct cifsInodeInfo *cinode)
90538c8a9a5SSteve French {
90638c8a9a5SSteve French 	return CIFSSMBLock(0, tcon, net_fid, current->tgid, 0, 0, 0, 0,
90738c8a9a5SSteve French 			   LOCKING_ANDX_OPLOCK_RELEASE, false, CIFS_CACHE_READ(cinode) ? 1 : 0);
90838c8a9a5SSteve French }
90938c8a9a5SSteve French 
91038c8a9a5SSteve French static int
cifs_queryfs(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,struct kstatfs * buf)91138c8a9a5SSteve French cifs_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
91238c8a9a5SSteve French 	     struct cifs_sb_info *cifs_sb, struct kstatfs *buf)
91338c8a9a5SSteve French {
91438c8a9a5SSteve French 	int rc = -EOPNOTSUPP;
91538c8a9a5SSteve French 
91638c8a9a5SSteve French 	buf->f_type = CIFS_SUPER_MAGIC;
91738c8a9a5SSteve French 
91838c8a9a5SSteve French 	/*
91938c8a9a5SSteve French 	 * We could add a second check for a QFS Unix capability bit
92038c8a9a5SSteve French 	 */
92138c8a9a5SSteve French 	if ((tcon->ses->capabilities & CAP_UNIX) &&
92238c8a9a5SSteve French 	    (CIFS_POSIX_EXTENSIONS & le64_to_cpu(tcon->fsUnixInfo.Capability)))
92338c8a9a5SSteve French 		rc = CIFSSMBQFSPosixInfo(xid, tcon, buf);
92438c8a9a5SSteve French 
92538c8a9a5SSteve French 	/*
92638c8a9a5SSteve French 	 * Only need to call the old QFSInfo if failed on newer one,
92738c8a9a5SSteve French 	 * e.g. by OS/2.
92838c8a9a5SSteve French 	 **/
92938c8a9a5SSteve French 	if (rc && (tcon->ses->capabilities & CAP_NT_SMBS))
93038c8a9a5SSteve French 		rc = CIFSSMBQFSInfo(xid, tcon, buf);
93138c8a9a5SSteve French 
93238c8a9a5SSteve French 	/*
93338c8a9a5SSteve French 	 * Some old Windows servers also do not support level 103, retry with
93438c8a9a5SSteve French 	 * older level one if old server failed the previous call or we
93538c8a9a5SSteve French 	 * bypassed it because we detected that this was an older LANMAN sess
93638c8a9a5SSteve French 	 */
93738c8a9a5SSteve French 	if (rc)
93838c8a9a5SSteve French 		rc = SMBOldQFSInfo(xid, tcon, buf);
93938c8a9a5SSteve French 	return rc;
94038c8a9a5SSteve French }
94138c8a9a5SSteve French 
94238c8a9a5SSteve French static int
cifs_mand_lock(const unsigned int xid,struct cifsFileInfo * cfile,__u64 offset,__u64 length,__u32 type,int lock,int unlock,bool wait)94338c8a9a5SSteve French cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
94438c8a9a5SSteve French 	       __u64 length, __u32 type, int lock, int unlock, bool wait)
94538c8a9a5SSteve French {
94638c8a9a5SSteve French 	return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->fid.netfid,
94738c8a9a5SSteve French 			   current->tgid, length, offset, unlock, lock,
94838c8a9a5SSteve French 			   (__u8)type, wait, 0);
94938c8a9a5SSteve French }
95038c8a9a5SSteve French 
95138c8a9a5SSteve French static int
cifs_unix_dfs_readlink(const unsigned int xid,struct cifs_tcon * tcon,const unsigned char * searchName,char ** symlinkinfo,const struct nls_table * nls_codepage)95238c8a9a5SSteve French cifs_unix_dfs_readlink(const unsigned int xid, struct cifs_tcon *tcon,
95338c8a9a5SSteve French 		       const unsigned char *searchName, char **symlinkinfo,
95438c8a9a5SSteve French 		       const struct nls_table *nls_codepage)
95538c8a9a5SSteve French {
95638c8a9a5SSteve French #ifdef CONFIG_CIFS_DFS_UPCALL
95738c8a9a5SSteve French 	int rc;
95838c8a9a5SSteve French 	struct dfs_info3_param referral = {0};
95938c8a9a5SSteve French 
96038c8a9a5SSteve French 	rc = get_dfs_path(xid, tcon->ses, searchName, nls_codepage, &referral,
96138c8a9a5SSteve French 			  0);
96238c8a9a5SSteve French 
96338c8a9a5SSteve French 	if (!rc) {
96438c8a9a5SSteve French 		*symlinkinfo = kstrdup(referral.node_name, GFP_KERNEL);
96538c8a9a5SSteve French 		free_dfs_info_param(&referral);
96638c8a9a5SSteve French 		if (!*symlinkinfo)
96738c8a9a5SSteve French 			rc = -ENOMEM;
96838c8a9a5SSteve French 	}
96938c8a9a5SSteve French 	return rc;
97038c8a9a5SSteve French #else /* No DFS support */
97138c8a9a5SSteve French 	return -EREMOTE;
97238c8a9a5SSteve French #endif
97338c8a9a5SSteve French }
97438c8a9a5SSteve French 
cifs_query_symlink(const unsigned int xid,struct cifs_tcon * tcon,struct cifs_sb_info * cifs_sb,const char * full_path,char ** target_path)9759a49e221SPaulo Alcantara static int cifs_query_symlink(const unsigned int xid,
9769a49e221SPaulo Alcantara 			      struct cifs_tcon *tcon,
9779a49e221SPaulo Alcantara 			      struct cifs_sb_info *cifs_sb,
9789a49e221SPaulo Alcantara 			      const char *full_path,
9794d07e5dfSPaulo Alcantara 			      char **target_path)
9804d07e5dfSPaulo Alcantara {
9814d07e5dfSPaulo Alcantara 	int rc;
9824d07e5dfSPaulo Alcantara 
9834d07e5dfSPaulo Alcantara 	cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path);
9844d07e5dfSPaulo Alcantara 
9854d07e5dfSPaulo Alcantara 	if (!cap_unix(tcon->ses))
9864d07e5dfSPaulo Alcantara 		return -EOPNOTSUPP;
9874d07e5dfSPaulo Alcantara 
9884d07e5dfSPaulo Alcantara 	rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path,
9894d07e5dfSPaulo Alcantara 				     cifs_sb->local_nls, cifs_remap(cifs_sb));
9904d07e5dfSPaulo Alcantara 	if (rc == -EREMOTE)
9914d07e5dfSPaulo Alcantara 		rc = cifs_unix_dfs_readlink(xid, tcon, full_path,
9924d07e5dfSPaulo Alcantara 					    target_path, cifs_sb->local_nls);
9934d07e5dfSPaulo Alcantara 	return rc;
9944d07e5dfSPaulo Alcantara }
9954d07e5dfSPaulo Alcantara 
cifs_parse_reparse_point(struct cifs_sb_info * cifs_sb,struct kvec * rsp_iov,struct cifs_open_info_data * data)9964d07e5dfSPaulo Alcantara static int cifs_parse_reparse_point(struct cifs_sb_info *cifs_sb,
9974d07e5dfSPaulo Alcantara 				    struct kvec *rsp_iov,
9984d07e5dfSPaulo Alcantara 				    struct cifs_open_info_data *data)
99938c8a9a5SSteve French {
1000d5c959a1SPaulo Alcantara 	struct reparse_data_buffer *buf;
1001d5c959a1SPaulo Alcantara 	TRANSACT_IOCTL_RSP *io = rsp_iov->iov_base;
1002d5c959a1SPaulo Alcantara 	bool unicode = !!(io->hdr.Flags2 & SMBFLG2_UNICODE);
1003d5c959a1SPaulo Alcantara 	u32 plen = le16_to_cpu(io->ByteCount);
100438c8a9a5SSteve French 
1005d5c959a1SPaulo Alcantara 	buf = (struct reparse_data_buffer *)((__u8 *)&io->hdr.Protocol +
1006d5c959a1SPaulo Alcantara 					     le32_to_cpu(io->DataOffset));
1007df32e887SPaulo Alcantara 	return parse_reparse_point(buf, plen, cifs_sb, unicode, data);
100838c8a9a5SSteve French }
100938c8a9a5SSteve French 
101038c8a9a5SSteve French static bool
cifs_is_read_op(__u32 oplock)101138c8a9a5SSteve French cifs_is_read_op(__u32 oplock)
101238c8a9a5SSteve French {
101338c8a9a5SSteve French 	return oplock == OPLOCK_READ;
101438c8a9a5SSteve French }
101538c8a9a5SSteve French 
101638c8a9a5SSteve French static unsigned int
cifs_wp_retry_size(struct inode * inode)101738c8a9a5SSteve French cifs_wp_retry_size(struct inode *inode)
101838c8a9a5SSteve French {
101938c8a9a5SSteve French 	return CIFS_SB(inode->i_sb)->ctx->wsize;
102038c8a9a5SSteve French }
102138c8a9a5SSteve French 
102238c8a9a5SSteve French static bool
cifs_dir_needs_close(struct cifsFileInfo * cfile)102338c8a9a5SSteve French cifs_dir_needs_close(struct cifsFileInfo *cfile)
102438c8a9a5SSteve French {
102538c8a9a5SSteve French 	return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
102638c8a9a5SSteve French }
102738c8a9a5SSteve French 
102838c8a9a5SSteve French static bool
cifs_can_echo(struct TCP_Server_Info * server)102938c8a9a5SSteve French cifs_can_echo(struct TCP_Server_Info *server)
103038c8a9a5SSteve French {
103138c8a9a5SSteve French 	if (server->tcpStatus == CifsGood)
103238c8a9a5SSteve French 		return true;
103338c8a9a5SSteve French 
103438c8a9a5SSteve French 	return false;
103538c8a9a5SSteve French }
103638c8a9a5SSteve French 
103738c8a9a5SSteve French static int
cifs_make_node(unsigned int xid,struct inode * inode,struct dentry * dentry,struct cifs_tcon * tcon,const char * full_path,umode_t mode,dev_t dev)103838c8a9a5SSteve French cifs_make_node(unsigned int xid, struct inode *inode,
103938c8a9a5SSteve French 	       struct dentry *dentry, struct cifs_tcon *tcon,
104038c8a9a5SSteve French 	       const char *full_path, umode_t mode, dev_t dev)
104138c8a9a5SSteve French {
104238c8a9a5SSteve French 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
104338c8a9a5SSteve French 	struct inode *newinode = NULL;
1044abea3c9aSSteve French 	int rc;
104538c8a9a5SSteve French 
104638c8a9a5SSteve French 	if (tcon->unix_ext) {
104738c8a9a5SSteve French 		/*
104838c8a9a5SSteve French 		 * SMB1 Unix Extensions: requires server support but
104938c8a9a5SSteve French 		 * works with all special files
105038c8a9a5SSteve French 		 */
105138c8a9a5SSteve French 		struct cifs_unix_set_info_args args = {
105238c8a9a5SSteve French 			.mode	= mode & ~current_umask(),
105338c8a9a5SSteve French 			.ctime	= NO_CHANGE_64,
105438c8a9a5SSteve French 			.atime	= NO_CHANGE_64,
105538c8a9a5SSteve French 			.mtime	= NO_CHANGE_64,
105638c8a9a5SSteve French 			.device	= dev,
105738c8a9a5SSteve French 		};
105838c8a9a5SSteve French 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
105938c8a9a5SSteve French 			args.uid = current_fsuid();
106038c8a9a5SSteve French 			args.gid = current_fsgid();
106138c8a9a5SSteve French 		} else {
106238c8a9a5SSteve French 			args.uid = INVALID_UID; /* no change */
106338c8a9a5SSteve French 			args.gid = INVALID_GID; /* no change */
106438c8a9a5SSteve French 		}
106538c8a9a5SSteve French 		rc = CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
106638c8a9a5SSteve French 					    cifs_sb->local_nls,
106738c8a9a5SSteve French 					    cifs_remap(cifs_sb));
106838c8a9a5SSteve French 		if (rc)
106938c8a9a5SSteve French 			return rc;
107038c8a9a5SSteve French 
107138c8a9a5SSteve French 		rc = cifs_get_inode_info_unix(&newinode, full_path,
107238c8a9a5SSteve French 					      inode->i_sb, xid);
107338c8a9a5SSteve French 
107438c8a9a5SSteve French 		if (rc == 0)
107538c8a9a5SSteve French 			d_instantiate(dentry, newinode);
107638c8a9a5SSteve French 		return rc;
107738c8a9a5SSteve French 	}
107838c8a9a5SSteve French 	/*
1079abea3c9aSSteve French 	 * Check if mounted with mount parm 'sfu' mount parm.
1080abea3c9aSSteve French 	 * SFU emulation should work with all servers, but only
1081abea3c9aSSteve French 	 * supports block and char device (no socket & fifo),
1082abea3c9aSSteve French 	 * and was used by default in earlier versions of Windows
108338c8a9a5SSteve French 	 */
108438c8a9a5SSteve French 	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
1085abea3c9aSSteve French 		return -EPERM;
1086abea3c9aSSteve French 	return cifs_sfu_make_node(xid, inode, dentry, tcon,
1087abea3c9aSSteve French 				  full_path, mode, dev);
108838c8a9a5SSteve French }
108938c8a9a5SSteve French 
109038c8a9a5SSteve French struct smb_version_operations smb1_operations = {
109138c8a9a5SSteve French 	.send_cancel = send_nt_cancel,
109238c8a9a5SSteve French 	.compare_fids = cifs_compare_fids,
109338c8a9a5SSteve French 	.setup_request = cifs_setup_request,
109438c8a9a5SSteve French 	.setup_async_request = cifs_setup_async_request,
109538c8a9a5SSteve French 	.check_receive = cifs_check_receive,
109638c8a9a5SSteve French 	.add_credits = cifs_add_credits,
109738c8a9a5SSteve French 	.set_credits = cifs_set_credits,
109838c8a9a5SSteve French 	.get_credits_field = cifs_get_credits_field,
109938c8a9a5SSteve French 	.get_credits = cifs_get_credits,
110038c8a9a5SSteve French 	.wait_mtu_credits = cifs_wait_mtu_credits,
110138c8a9a5SSteve French 	.get_next_mid = cifs_get_next_mid,
110238c8a9a5SSteve French 	.read_data_offset = cifs_read_data_offset,
110338c8a9a5SSteve French 	.read_data_length = cifs_read_data_length,
110438c8a9a5SSteve French 	.map_error = map_smb_to_linux_error,
110538c8a9a5SSteve French 	.find_mid = cifs_find_mid,
110638c8a9a5SSteve French 	.check_message = checkSMB,
110738c8a9a5SSteve French 	.dump_detail = cifs_dump_detail,
110838c8a9a5SSteve French 	.clear_stats = cifs_clear_stats,
110938c8a9a5SSteve French 	.print_stats = cifs_print_stats,
111038c8a9a5SSteve French 	.is_oplock_break = is_valid_oplock_break,
111138c8a9a5SSteve French 	.downgrade_oplock = cifs_downgrade_oplock,
111238c8a9a5SSteve French 	.check_trans2 = cifs_check_trans2,
111338c8a9a5SSteve French 	.need_neg = cifs_need_neg,
111438c8a9a5SSteve French 	.negotiate = cifs_negotiate,
111538c8a9a5SSteve French 	.negotiate_wsize = cifs_negotiate_wsize,
111638c8a9a5SSteve French 	.negotiate_rsize = cifs_negotiate_rsize,
111738c8a9a5SSteve French 	.sess_setup = CIFS_SessSetup,
111838c8a9a5SSteve French 	.logoff = CIFSSMBLogoff,
111938c8a9a5SSteve French 	.tree_connect = CIFSTCon,
112038c8a9a5SSteve French 	.tree_disconnect = CIFSSMBTDis,
112138c8a9a5SSteve French 	.get_dfs_refer = CIFSGetDFSRefer,
112238c8a9a5SSteve French 	.qfs_tcon = cifs_qfs_tcon,
112338c8a9a5SSteve French 	.is_path_accessible = cifs_is_path_accessible,
112438c8a9a5SSteve French 	.can_echo = cifs_can_echo,
112538c8a9a5SSteve French 	.query_path_info = cifs_query_path_info,
1126d5c959a1SPaulo Alcantara 	.query_reparse_point = cifs_query_reparse_point,
112738c8a9a5SSteve French 	.query_file_info = cifs_query_file_info,
112838c8a9a5SSteve French 	.get_srv_inum = cifs_get_srv_inum,
112938c8a9a5SSteve French 	.set_path_size = CIFSSMBSetEOF,
113038c8a9a5SSteve French 	.set_file_size = CIFSSMBSetFileSize,
113138c8a9a5SSteve French 	.set_file_info = smb_set_file_info,
113238c8a9a5SSteve French 	.set_compression = cifs_set_compression,
113338c8a9a5SSteve French 	.echo = CIFSSMBEcho,
113438c8a9a5SSteve French 	.mkdir = CIFSSMBMkDir,
113538c8a9a5SSteve French 	.mkdir_setinfo = cifs_mkdir_setinfo,
113638c8a9a5SSteve French 	.rmdir = CIFSSMBRmDir,
113738c8a9a5SSteve French 	.unlink = CIFSSMBDelFile,
113838c8a9a5SSteve French 	.rename_pending_delete = cifs_rename_pending_delete,
113938c8a9a5SSteve French 	.rename = CIFSSMBRename,
114038c8a9a5SSteve French 	.create_hardlink = CIFSCreateHardLink,
114138c8a9a5SSteve French 	.query_symlink = cifs_query_symlink,
11424d07e5dfSPaulo Alcantara 	.parse_reparse_point = cifs_parse_reparse_point,
114338c8a9a5SSteve French 	.open = cifs_open_file,
114438c8a9a5SSteve French 	.set_fid = cifs_set_fid,
114538c8a9a5SSteve French 	.close = cifs_close_file,
114638c8a9a5SSteve French 	.flush = cifs_flush_file,
114738c8a9a5SSteve French 	.async_readv = cifs_async_readv,
114838c8a9a5SSteve French 	.async_writev = cifs_async_writev,
114938c8a9a5SSteve French 	.sync_read = cifs_sync_read,
115038c8a9a5SSteve French 	.sync_write = cifs_sync_write,
115138c8a9a5SSteve French 	.query_dir_first = cifs_query_dir_first,
115238c8a9a5SSteve French 	.query_dir_next = cifs_query_dir_next,
115338c8a9a5SSteve French 	.close_dir = cifs_close_dir,
115438c8a9a5SSteve French 	.calc_smb_size = smbCalcSize,
115538c8a9a5SSteve French 	.oplock_response = cifs_oplock_response,
115638c8a9a5SSteve French 	.queryfs = cifs_queryfs,
115738c8a9a5SSteve French 	.mand_lock = cifs_mand_lock,
115838c8a9a5SSteve French 	.mand_unlock_range = cifs_unlock_range,
115938c8a9a5SSteve French 	.push_mand_locks = cifs_push_mandatory_locks,
116038c8a9a5SSteve French 	.query_mf_symlink = cifs_query_mf_symlink,
116138c8a9a5SSteve French 	.create_mf_symlink = cifs_create_mf_symlink,
116238c8a9a5SSteve French 	.is_read_op = cifs_is_read_op,
116338c8a9a5SSteve French 	.wp_retry_size = cifs_wp_retry_size,
116438c8a9a5SSteve French 	.dir_needs_close = cifs_dir_needs_close,
116538c8a9a5SSteve French 	.select_sectype = cifs_select_sectype,
116638c8a9a5SSteve French #ifdef CONFIG_CIFS_XATTR
116738c8a9a5SSteve French 	.query_all_EAs = CIFSSMBQAllEAs,
116838c8a9a5SSteve French 	.set_EA = CIFSSMBSetEA,
116938c8a9a5SSteve French #endif /* CIFS_XATTR */
117038c8a9a5SSteve French 	.get_acl = get_cifs_acl,
117138c8a9a5SSteve French 	.get_acl_by_fid = get_cifs_acl_by_fid,
117238c8a9a5SSteve French 	.set_acl = set_cifs_acl,
117338c8a9a5SSteve French 	.make_node = cifs_make_node,
117438c8a9a5SSteve French };
117538c8a9a5SSteve French 
117638c8a9a5SSteve French struct smb_version_values smb1_values = {
117738c8a9a5SSteve French 	.version_string = SMB1_VERSION_STRING,
117838c8a9a5SSteve French 	.protocol_id = SMB10_PROT_ID,
117938c8a9a5SSteve French 	.large_lock_type = LOCKING_ANDX_LARGE_FILES,
118038c8a9a5SSteve French 	.exclusive_lock_type = 0,
118138c8a9a5SSteve French 	.shared_lock_type = LOCKING_ANDX_SHARED_LOCK,
118238c8a9a5SSteve French 	.unlock_lock_type = 0,
118338c8a9a5SSteve French 	.header_preamble_size = 4,
118438c8a9a5SSteve French 	.header_size = sizeof(struct smb_hdr),
118538c8a9a5SSteve French 	.max_header_size = MAX_CIFS_HDR_SIZE,
118638c8a9a5SSteve French 	.read_rsp_size = sizeof(READ_RSP),
118738c8a9a5SSteve French 	.lock_cmd = cpu_to_le16(SMB_COM_LOCKING_ANDX),
118838c8a9a5SSteve French 	.cap_unix = CAP_UNIX,
118938c8a9a5SSteve French 	.cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
119038c8a9a5SSteve French 	.cap_large_files = CAP_LARGE_FILES,
119138c8a9a5SSteve French 	.signing_enabled = SECMODE_SIGN_ENABLED,
119238c8a9a5SSteve French 	.signing_required = SECMODE_SIGN_REQUIRED,
119338c8a9a5SSteve French };
1194