misc.c 23.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *   fs/cifs/misc.c
 *
S
Steve French 已提交
4
 *   Copyright (C) International Business Machines  Corp., 2002,2008
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
S
Steve French 已提交
19
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
L
Linus Torvalds 已提交
20 21 22 23 24
 */

#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/mempool.h>
25
#include <linux/vmalloc.h>
L
Linus Torvalds 已提交
26 27 28 29 30 31
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
#include "smberr.h"
#include "nterr.h"
32
#include "cifs_unicode.h"
33 34 35
#ifdef CONFIG_CIFS_SMB2
#include "smb2pdu.h"
#endif
L
Linus Torvalds 已提交
36 37 38 39

extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;

S
Steve French 已提交
40 41 42 43
/* The xid serves as a useful identifier for each incoming vfs request,
   in a similar way to the mid which is useful to track each sent smb,
   and CurrentXid can also provide a running counter (although it
   will eventually wrap past zero) of the total vfs operations handled
L
Linus Torvalds 已提交
44 45 46
   since the cifs fs was mounted */

unsigned int
47
_get_xid(void)
L
Linus Torvalds 已提交
48 49 50 51 52
{
	unsigned int xid;

	spin_lock(&GlobalMid_Lock);
	GlobalTotalActiveXid++;
53 54

	/* keep high water mark for number of simultaneous ops in filesystem */
L
Linus Torvalds 已提交
55
	if (GlobalTotalActiveXid > GlobalMaxActiveXid)
56
		GlobalMaxActiveXid = GlobalTotalActiveXid;
S
Steve French 已提交
57
	if (GlobalTotalActiveXid > 65000)
58
		cifs_dbg(FYI, "warning: more than 65000 requests active\n");
L
Linus Torvalds 已提交
59 60 61 62 63 64
	xid = GlobalCurrentXid++;
	spin_unlock(&GlobalMid_Lock);
	return xid;
}

void
65
_free_xid(unsigned int xid)
L
Linus Torvalds 已提交
66 67
{
	spin_lock(&GlobalMid_Lock);
S
Steve French 已提交
68
	/* if (GlobalTotalActiveXid == 0)
L
Linus Torvalds 已提交
69 70 71 72 73
		BUG(); */
	GlobalTotalActiveXid--;
	spin_unlock(&GlobalMid_Lock);
}

74
struct cifs_ses *
L
Linus Torvalds 已提交
75 76
sesInfoAlloc(void)
{
77
	struct cifs_ses *ret_buf;
L
Linus Torvalds 已提交
78

79
	ret_buf = kzalloc(sizeof(struct cifs_ses), GFP_KERNEL);
L
Linus Torvalds 已提交
80 81 82
	if (ret_buf) {
		atomic_inc(&sesInfoAllocCount);
		ret_buf->status = CifsNew;
83 84
		++ret_buf->ses_count;
		INIT_LIST_HEAD(&ret_buf->smb_ses_list);
85
		INIT_LIST_HEAD(&ret_buf->tcon_list);
86
		mutex_init(&ret_buf->session_mutex);
L
Linus Torvalds 已提交
87 88 89 90 91
	}
	return ret_buf;
}

void
92
sesInfoFree(struct cifs_ses *buf_to_free)
L
Linus Torvalds 已提交
93 94
{
	if (buf_to_free == NULL) {
95
		cifs_dbg(FYI, "Null buffer passed to sesInfoFree\n");
L
Linus Torvalds 已提交
96 97 98 99
		return;
	}

	atomic_dec(&sesInfoAllocCount);
J
Jesper Juhl 已提交
100 101 102
	kfree(buf_to_free->serverOS);
	kfree(buf_to_free->serverDomain);
	kfree(buf_to_free->serverNOS);
103 104 105 106
	if (buf_to_free->password) {
		memset(buf_to_free->password, 0, strlen(buf_to_free->password));
		kfree(buf_to_free->password);
	}
107
	kfree(buf_to_free->user_name);
108
	kfree(buf_to_free->domainName);
109
	kfree(buf_to_free->auth_key.response);
L
Linus Torvalds 已提交
110 111 112
	kfree(buf_to_free);
}

113
struct cifs_tcon *
L
Linus Torvalds 已提交
114 115
tconInfoAlloc(void)
{
116 117
	struct cifs_tcon *ret_buf;
	ret_buf = kzalloc(sizeof(struct cifs_tcon), GFP_KERNEL);
L
Linus Torvalds 已提交
118 119 120
	if (ret_buf) {
		atomic_inc(&tconInfoAllocCount);
		ret_buf->tidStatus = CifsNew;
121
		++ret_buf->tc_count;
L
Linus Torvalds 已提交
122
		INIT_LIST_HEAD(&ret_buf->openFileList);
123
		INIT_LIST_HEAD(&ret_buf->tcon_list);
124
		spin_lock_init(&ret_buf->open_file_lock);
L
Linus Torvalds 已提交
125 126 127 128 129 130 131 132
#ifdef CONFIG_CIFS_STATS
		spin_lock_init(&ret_buf->stat_lock);
#endif
	}
	return ret_buf;
}

void
133
tconInfoFree(struct cifs_tcon *buf_to_free)
L
Linus Torvalds 已提交
134 135
{
	if (buf_to_free == NULL) {
136
		cifs_dbg(FYI, "Null buffer passed to tconInfoFree\n");
L
Linus Torvalds 已提交
137 138 139
		return;
	}
	atomic_dec(&tconInfoAllocCount);
J
Jesper Juhl 已提交
140
	kfree(buf_to_free->nativeFileSystem);
J
Jeff Layton 已提交
141 142 143 144
	if (buf_to_free->password) {
		memset(buf_to_free->password, 0, strlen(buf_to_free->password));
		kfree(buf_to_free->password);
	}
L
Linus Torvalds 已提交
145 146 147 148 149 150 151
	kfree(buf_to_free);
}

struct smb_hdr *
cifs_buf_get(void)
{
	struct smb_hdr *ret_buf = NULL;
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
	size_t buf_size = sizeof(struct smb_hdr);

#ifdef CONFIG_CIFS_SMB2
	/*
	 * SMB2 header is bigger than CIFS one - no problems to clean some
	 * more bytes for CIFS.
	 */
	buf_size = sizeof(struct smb2_hdr);
#endif
	/*
	 * We could use negotiated size instead of max_msgsize -
	 * but it may be more efficient to always alloc same size
	 * albeit slightly larger than necessary and maxbuffersize
	 * defaults to this and can not be bigger.
	 */
167
	ret_buf = mempool_alloc(cifs_req_poolp, GFP_NOFS);
L
Linus Torvalds 已提交
168 169 170

	/* clear the first few header bytes */
	/* for most paths, more is cleared in header_assemble */
171 172
	memset(ret_buf, 0, buf_size + 3);
	atomic_inc(&bufAllocCount);
173
#ifdef CONFIG_CIFS_STATS2
174
	atomic_inc(&totBufAllocCount);
175
#endif /* CONFIG_CIFS_STATS2 */
L
Linus Torvalds 已提交
176 177 178 179 180 181 182 183

	return ret_buf;
}

void
cifs_buf_release(void *buf_to_free)
{
	if (buf_to_free == NULL) {
184
		/* cifs_dbg(FYI, "Null buffer passed to cifs_buf_release\n");*/
L
Linus Torvalds 已提交
185 186
		return;
	}
S
Steve French 已提交
187
	mempool_free(buf_to_free, cifs_req_poolp);
L
Linus Torvalds 已提交
188 189 190 191 192 193 194 195 196 197

	atomic_dec(&bufAllocCount);
	return;
}

struct smb_hdr *
cifs_small_buf_get(void)
{
	struct smb_hdr *ret_buf = NULL;

S
Steve French 已提交
198 199 200
/* We could use negotiated size instead of max_msgsize -
   but it may be more efficient to always alloc same size
   albeit slightly larger than necessary and maxbuffersize
L
Linus Torvalds 已提交
201
   defaults to this and can not be bigger */
202
	ret_buf = mempool_alloc(cifs_sm_req_poolp, GFP_NOFS);
L
Linus Torvalds 已提交
203 204
	/* No need to clear memory here, cleared in header assemble */
	/*	memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
205
	atomic_inc(&smBufAllocCount);
206
#ifdef CONFIG_CIFS_STATS2
207
	atomic_inc(&totSmBufAllocCount);
208 209
#endif /* CONFIG_CIFS_STATS2 */

L
Linus Torvalds 已提交
210 211 212 213 214 215 216 217
	return ret_buf;
}

void
cifs_small_buf_release(void *buf_to_free)
{

	if (buf_to_free == NULL) {
218
		cifs_dbg(FYI, "Null buffer passed to cifs_small_buf_release\n");
L
Linus Torvalds 已提交
219 220
		return;
	}
S
Steve French 已提交
221
	mempool_free(buf_to_free, cifs_sm_req_poolp);
L
Linus Torvalds 已提交
222 223 224 225 226

	atomic_dec(&smBufAllocCount);
	return;
}

227 228 229 230 231 232 233 234 235
void
free_rsp_buf(int resp_buftype, void *rsp)
{
	if (resp_buftype == CIFS_SMALL_BUFFER)
		cifs_small_buf_release(rsp);
	else if (resp_buftype == CIFS_LARGE_BUFFER)
		cifs_buf_release(rsp);
}

236 237
/* NB: MID can not be set if treeCon not passed in, in that
   case it is responsbility of caller to set the mid */
L
Linus Torvalds 已提交
238 239
void
header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
240
		const struct cifs_tcon *treeCon, int word_count
L
Linus Torvalds 已提交
241 242 243 244
		/* length of fixed section (word count) in two byte units  */)
{
	char *temp = (char *) buffer;

S
Steve French 已提交
245
	memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
L
Linus Torvalds 已提交
246

247
	buffer->smb_buf_length = cpu_to_be32(
S
Steve French 已提交
248
	    (2 * word_count) + sizeof(struct smb_hdr) -
L
Linus Torvalds 已提交
249
	    4 /*  RFC 1001 length field does not count */  +
250
	    2 /* for bcc field itself */) ;
L
Linus Torvalds 已提交
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265

	buffer->Protocol[0] = 0xFF;
	buffer->Protocol[1] = 'S';
	buffer->Protocol[2] = 'M';
	buffer->Protocol[3] = 'B';
	buffer->Command = smb_command;
	buffer->Flags = 0x00;	/* case sensitive */
	buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
	buffer->Pid = cpu_to_le16((__u16)current->tgid);
	buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
	if (treeCon) {
		buffer->Tid = treeCon->tid;
		if (treeCon->ses) {
			if (treeCon->ses->capabilities & CAP_UNICODE)
				buffer->Flags2 |= SMBFLG2_UNICODE;
S
Steve French 已提交
266
			if (treeCon->ses->capabilities & CAP_STATUS32)
L
Linus Torvalds 已提交
267
				buffer->Flags2 |= SMBFLG2_ERR_STATUS;
S
Steve French 已提交
268

269 270
			/* Uid is not converted */
			buffer->Uid = treeCon->ses->Suid;
271
			buffer->Mid = get_next_mid(treeCon->ses->server);
L
Linus Torvalds 已提交
272 273 274
		}
		if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
			buffer->Flags2 |= SMBFLG2_DFS;
275 276
		if (treeCon->nocase)
			buffer->Flags  |= SMBFLG_CASELESS;
S
Steve French 已提交
277
		if ((treeCon->ses) && (treeCon->ses->server))
278
			if (treeCon->ses->server->sign)
L
Linus Torvalds 已提交
279 280 281 282 283 284 285 286
				buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
	}

/*  endian conversion of flags is now done just before sending */
	buffer->WordCount = (char) word_count;
	return;
}

287
static int
288
check_smb_hdr(struct smb_hdr *smb)
L
Linus Torvalds 已提交
289
{
290 291
	/* does it have the right SMB "signature" ? */
	if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) {
292 293
		cifs_dbg(VFS, "Bad protocol string signature header 0x%x\n",
			 *(unsigned int *)smb->Protocol);
294 295 296 297 298 299 300 301 302 303 304
		return 1;
	}

	/* if it's a response then accept */
	if (smb->Flags & SMBFLG_RESPONSE)
		return 0;

	/* only one valid case where server sends us request */
	if (smb->Command == SMB_COM_LOCKING_ANDX)
		return 0;

305 306
	cifs_dbg(VFS, "Server sent request, not response. mid=%u\n",
		 get_mid(smb));
L
Linus Torvalds 已提交
307 308 309 310
	return 1;
}

int
311
checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server)
L
Linus Torvalds 已提交
312
{
313
	struct smb_hdr *smb = (struct smb_hdr *)buf;
J
Jeff Layton 已提交
314
	__u32 rfclen = be32_to_cpu(smb->smb_buf_length);
315
	__u32 clc_len;  /* calculated length */
316 317
	cifs_dbg(FYI, "checkSMB Length: 0x%x, smb_buf_length: 0x%x\n",
		 total_read, rfclen);
318

J
Jeff Layton 已提交
319 320 321
	/* is this frame too small to even get to a BCC? */
	if (total_read < 2 + sizeof(struct smb_hdr)) {
		if ((total_read >= sizeof(struct smb_hdr) - 1)
L
Linus Torvalds 已提交
322
			    && (smb->Status.CifsError != 0)) {
J
Jeff Layton 已提交
323
			/* it's an error return */
324 325 326
			smb->WordCount = 0;
			/* some error cases do not return wct and bcc */
			return 0;
J
Jeff Layton 已提交
327
		} else if ((total_read == sizeof(struct smb_hdr) + 1) &&
328
				(smb->WordCount == 0)) {
S
Steve French 已提交
329
			char *tmp = (char *)smb;
330 331 332 333 334 335 336 337 338 339 340
			/* Need to work around a bug in two servers here */
			/* First, check if the part of bcc they sent was zero */
			if (tmp[sizeof(struct smb_hdr)] == 0) {
				/* some servers return only half of bcc
				 * on simple responses (wct, bcc both zero)
				 * in particular have seen this on
				 * ulogoffX and FindClose. This leaves
				 * one byte of bcc potentially unitialized
				 */
				/* zero rest of bcc */
				tmp[sizeof(struct smb_hdr)+1] = 0;
341
				return 0;
L
Linus Torvalds 已提交
342
			}
343
			cifs_dbg(VFS, "rcvd invalid byte count (bcc)\n");
344
		} else {
345
			cifs_dbg(VFS, "Length less than smb header size\n");
L
Linus Torvalds 已提交
346
		}
J
Jeff Layton 已提交
347
		return -EIO;
L
Linus Torvalds 已提交
348 349
	}

J
Jeff Layton 已提交
350
	/* otherwise, there is enough to get to the BCC */
351
	if (check_smb_hdr(smb))
J
Jeff Layton 已提交
352
		return -EIO;
353
	clc_len = smbCalcSize(smb);
354

J
Jeff Layton 已提交
355
	if (4 + rfclen != total_read) {
356 357
		cifs_dbg(VFS, "Length read does not match RFC1001 length %d\n",
			 rfclen);
J
Jeff Layton 已提交
358
		return -EIO;
359 360
	}

J
Jeff Layton 已提交
361
	if (4 + rfclen != clc_len) {
362
		__u16 mid = get_mid(smb);
363
		/* check if bcc wrapped around for large read responses */
J
Jeff Layton 已提交
364
		if ((rfclen > 64 * 1024) && (rfclen > clc_len)) {
365
			/* check if lengths match mod 64K */
J
Jeff Layton 已提交
366
			if (((4 + rfclen) & 0xFFFF) == (clc_len & 0xFFFF))
S
Steve French 已提交
367
				return 0; /* bcc wrapped */
368
		}
369
		cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u\n",
370
			 clc_len, 4 + rfclen, mid);
371

J
Jeff Layton 已提交
372
		if (4 + rfclen < clc_len) {
373
			cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n",
374
				 rfclen, mid);
J
Jeff Layton 已提交
375 376
			return -EIO;
		} else if (rfclen > clc_len + 512) {
377 378 379 380 381 382 383 384 385
			/*
			 * Some servers (Windows XP in particular) send more
			 * data than the lengths in the SMB packet would
			 * indicate on certain calls (byte range locks and
			 * trans2 find first calls in particular). While the
			 * client can handle such a frame by ignoring the
			 * trailing data, we choose limit the amount of extra
			 * data to 512 bytes.
			 */
386
			cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n",
387
				 rfclen, mid);
J
Jeff Layton 已提交
388
			return -EIO;
389
		}
L
Linus Torvalds 已提交
390
	}
391
	return 0;
L
Linus Torvalds 已提交
392
}
393 394

bool
395
is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
S
Steve French 已提交
396
{
397
	struct smb_hdr *buf = (struct smb_hdr *)buffer;
S
Steve French 已提交
398
	struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
399
	struct list_head *tmp, *tmp1, *tmp2;
400 401
	struct cifs_ses *ses;
	struct cifs_tcon *tcon;
402
	struct cifsInodeInfo *pCifsInode;
L
Linus Torvalds 已提交
403 404
	struct cifsFileInfo *netfile;

405
	cifs_dbg(FYI, "Checking for oplock break or dnotify response\n");
S
Steve French 已提交
406
	if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
L
Linus Torvalds 已提交
407
	   (pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
S
Steve French 已提交
408
		struct smb_com_transaction_change_notify_rsp *pSMBr =
L
Linus Torvalds 已提交
409
			(struct smb_com_transaction_change_notify_rsp *)buf;
S
Steve French 已提交
410
		struct file_notify_information *pnotify;
L
Linus Torvalds 已提交
411
		__u32 data_offset = 0;
412
		if (get_bcc(buf) > sizeof(struct file_notify_information)) {
L
Linus Torvalds 已提交
413 414
			data_offset = le32_to_cpu(pSMBr->DataOffset);

415 416
			pnotify = (struct file_notify_information *)
				((char *)&pSMBr->hdr.Protocol + data_offset);
417
			cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n",
418
				 pnotify->FileName, pnotify->Action);
S
Steve French 已提交
419
			/*   cifs_dump_mem("Rcvd notify Data: ",buf,
420
				sizeof(struct smb_hdr)+60); */
421
			return true;
L
Linus Torvalds 已提交
422
		}
S
Steve French 已提交
423
		if (pSMBr->hdr.Status.CifsError) {
424
			cifs_dbg(FYI, "notify err 0x%x\n",
425
				 pSMBr->hdr.Status.CifsError);
426
			return true;
L
Linus Torvalds 已提交
427
		}
428
		return false;
S
Steve French 已提交
429
	}
S
Steve French 已提交
430
	if (pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
431
		return false;
S
Steve French 已提交
432
	if (pSMB->hdr.Flags & SMBFLG_RESPONSE) {
L
Linus Torvalds 已提交
433 434 435 436
		/* no sense logging error on invalid handle on oplock
		   break - harmless race between close request and oplock
		   break response is expected from time to time writing out
		   large dirty files cached on the client */
S
Steve French 已提交
437 438
		if ((NT_STATUS_INVALID_HANDLE) ==
		   le32_to_cpu(pSMB->hdr.Status.CifsError)) {
439
			cifs_dbg(FYI, "invalid handle on oplock break\n");
440
			return true;
S
Steve French 已提交
441
		} else if (ERRbadfid ==
L
Linus Torvalds 已提交
442
		   le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
443
			return true;
L
Linus Torvalds 已提交
444
		} else {
445
			return false; /* on valid oplock brk we get "request" */
L
Linus Torvalds 已提交
446 447
		}
	}
S
Steve French 已提交
448
	if (pSMB->hdr.WordCount != 8)
449
		return false;
L
Linus Torvalds 已提交
450

451
	cifs_dbg(FYI, "oplock type 0x%x level 0x%x\n",
452
		 pSMB->LockType, pSMB->OplockLevel);
S
Steve French 已提交
453
	if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
454
		return false;
L
Linus Torvalds 已提交
455 456

	/* look up tcon based on tid & uid */
457
	spin_lock(&cifs_tcp_ses_lock);
458
	list_for_each(tmp, &srv->smb_ses_list) {
459
		ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
460
		list_for_each(tmp1, &ses->tcon_list) {
461
			tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
462 463 464
			if (tcon->tid != buf->Tid)
				continue;

465
			cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
466
			spin_lock(&tcon->open_file_lock);
467 468
			list_for_each(tmp2, &tcon->openFileList) {
				netfile = list_entry(tmp2, struct cifsFileInfo,
469
						     tlist);
470
				if (pSMB->Fid != netfile->fid.netfid)
471 472
					continue;

473
				cifs_dbg(FYI, "file id match, oplock break\n");
474
				pCifsInode = CIFS_I(d_inode(netfile->dentry));
475

476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
				set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK,
					&pCifsInode->flags);

				/*
				 * Set flag if the server downgrades the oplock
				 * to L2 else clear.
				 */
				if (pSMB->OplockLevel)
					set_bit(
					   CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
					   &pCifsInode->flags);
				else
					clear_bit(
					   CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
					   &pCifsInode->flags);

J
Jeff Layton 已提交
492
				queue_work(cifsiod_wq,
493
					   &netfile->oplock_break);
494 495
				netfile->oplock_break_cancelled = false;

496
				spin_unlock(&tcon->open_file_lock);
497
				spin_unlock(&cifs_tcp_ses_lock);
498
				return true;
L
Linus Torvalds 已提交
499
			}
500
			spin_unlock(&tcon->open_file_lock);
501
			spin_unlock(&cifs_tcp_ses_lock);
502
			cifs_dbg(FYI, "No matching file for oplock break\n");
503
			return true;
L
Linus Torvalds 已提交
504 505
		}
	}
506
	spin_unlock(&cifs_tcp_ses_lock);
507
	cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n");
508
	return true;
L
Linus Torvalds 已提交
509 510 511
}

void
512
dump_smb(void *buf, int smb_buf_length)
L
Linus Torvalds 已提交
513 514 515 516
{
	if (traceSMB == 0)
		return;

517 518
	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, 8, 2, buf,
		       smb_buf_length, true);
L
Linus Torvalds 已提交
519
}
520

521 522 523 524
void
cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
{
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
525
		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
526 527
		cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s. This server doesn't seem to support them properly. Hardlinks will not be recognized on this mount. Consider mounting with the \"noserverino\" option to silence this message.\n",
			 cifs_sb_master_tcon(cifs_sb)->treeName);
528 529
	}
}
P
Pavel Shilovsky 已提交
530

531
void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
P
Pavel Shilovsky 已提交
532
{
533
	oplock &= 0xF;
P
Pavel Shilovsky 已提交
534

535
	if (oplock == OPLOCK_EXCLUSIVE) {
536
		cinode->oplock = CIFS_CACHE_WRITE_FLG | CIFS_CACHE_READ_FLG;
537 538
		cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
			 &cinode->vfs_inode);
539
	} else if (oplock == OPLOCK_READ) {
540
		cinode->oplock = CIFS_CACHE_READ_FLG;
541 542
		cifs_dbg(FYI, "Level II Oplock granted on inode %p\n",
			 &cinode->vfs_inode);
543 544
	} else
		cinode->oplock = 0;
P
Pavel Shilovsky 已提交
545
}
546

547 548 549 550 551 552 553 554 555 556
/*
 * We wait for oplock breaks to be processed before we attempt to perform
 * writes.
 */
int cifs_get_writer(struct cifsInodeInfo *cinode)
{
	int rc;

start:
	rc = wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK,
557
			 TASK_KILLABLE);
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
	if (rc)
		return rc;

	spin_lock(&cinode->writers_lock);
	if (!cinode->writers)
		set_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
	cinode->writers++;
	/* Check to see if we have started servicing an oplock break */
	if (test_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags)) {
		cinode->writers--;
		if (cinode->writers == 0) {
			clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
			wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS);
		}
		spin_unlock(&cinode->writers_lock);
		goto start;
	}
	spin_unlock(&cinode->writers_lock);
	return 0;
}

void cifs_put_writer(struct cifsInodeInfo *cinode)
{
	spin_lock(&cinode->writers_lock);
	cinode->writers--;
	if (cinode->writers == 0) {
		clear_bit(CIFS_INODE_PENDING_WRITERS, &cinode->flags);
		wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS);
	}
	spin_unlock(&cinode->writers_lock);
}

void cifs_done_oplock_break(struct cifsInodeInfo *cinode)
{
	clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags);
	wake_up_bit(&cinode->flags, CIFS_INODE_PENDING_OPLOCK_BREAK);
}

596 597 598 599
bool
backup_cred(struct cifs_sb_info *cifs_sb)
{
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) {
600
		if (uid_eq(cifs_sb->mnt_backupuid, current_fsuid()))
601 602 603 604 605 606 607 608 609
			return true;
	}
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) {
		if (in_group_p(cifs_sb->mnt_backupgid))
			return true;
	}

	return false;
}
610 611 612 613

void
cifs_del_pending_open(struct cifs_pending_open *open)
{
614
	spin_lock(&tlink_tcon(open->tlink)->open_file_lock);
615
	list_del(&open->olist);
616
	spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
}

void
cifs_add_pending_open_locked(struct cifs_fid *fid, struct tcon_link *tlink,
			     struct cifs_pending_open *open)
{
#ifdef CONFIG_CIFS_SMB2
	memcpy(open->lease_key, fid->lease_key, SMB2_LEASE_KEY_SIZE);
#endif
	open->oplock = CIFS_OPLOCK_NO_CHANGE;
	open->tlink = tlink;
	fid->pending_open = open;
	list_add_tail(&open->olist, &tlink_tcon(tlink)->pending_opens);
}

void
cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink,
		      struct cifs_pending_open *open)
{
636
	spin_lock(&tlink_tcon(tlink)->open_file_lock);
637
	cifs_add_pending_open_locked(fid, tlink, open);
638
	spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
639
}
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744

/* parses DFS refferal V3 structure
 * caller is responsible for freeing target_nodes
 * returns:
 * - on success - 0
 * - on failure - errno
 */
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)
{
	int i, rc = 0;
	char *data_end;
	struct dfs_referral_level_3 *ref;

	*num_of_nodes = le16_to_cpu(rsp->NumberOfReferrals);

	if (*num_of_nodes < 1) {
		cifs_dbg(VFS, "num_referrals: must be at least > 0, but we get num_referrals = %d\n",
			 *num_of_nodes);
		rc = -EINVAL;
		goto parse_DFS_referrals_exit;
	}

	ref = (struct dfs_referral_level_3 *) &(rsp->referrals);
	if (ref->VersionNumber != cpu_to_le16(3)) {
		cifs_dbg(VFS, "Referrals of V%d version are not supported, should be V3\n",
			 le16_to_cpu(ref->VersionNumber));
		rc = -EINVAL;
		goto parse_DFS_referrals_exit;
	}

	/* get the upper boundary of the resp buffer */
	data_end = (char *)rsp + rsp_size;

	cifs_dbg(FYI, "num_referrals: %d dfs flags: 0x%x ...\n",
		 *num_of_nodes, le32_to_cpu(rsp->DFSFlags));

	*target_nodes = kcalloc(*num_of_nodes, sizeof(struct dfs_info3_param),
				GFP_KERNEL);
	if (*target_nodes == NULL) {
		rc = -ENOMEM;
		goto parse_DFS_referrals_exit;
	}

	/* collect necessary data from referrals */
	for (i = 0; i < *num_of_nodes; i++) {
		char *temp;
		int max_len;
		struct dfs_info3_param *node = (*target_nodes)+i;

		node->flags = le32_to_cpu(rsp->DFSFlags);
		if (is_unicode) {
			__le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
						GFP_KERNEL);
			if (tmp == NULL) {
				rc = -ENOMEM;
				goto parse_DFS_referrals_exit;
			}
			cifsConvertToUTF16((__le16 *) tmp, searchName,
					   PATH_MAX, nls_codepage, remap);
			node->path_consumed = cifs_utf16_bytes(tmp,
					le16_to_cpu(rsp->PathConsumed),
					nls_codepage);
			kfree(tmp);
		} else
			node->path_consumed = le16_to_cpu(rsp->PathConsumed);

		node->server_type = le16_to_cpu(ref->ServerType);
		node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);

		/* copy DfsPath */
		temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
		max_len = data_end - temp;
		node->path_name = cifs_strndup_from_utf16(temp, max_len,
						is_unicode, nls_codepage);
		if (!node->path_name) {
			rc = -ENOMEM;
			goto parse_DFS_referrals_exit;
		}

		/* copy link target UNC */
		temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
		max_len = data_end - temp;
		node->node_name = cifs_strndup_from_utf16(temp, max_len,
						is_unicode, nls_codepage);
		if (!node->node_name) {
			rc = -ENOMEM;
			goto parse_DFS_referrals_exit;
		}

		ref++;
	}

parse_DFS_referrals_exit:
	if (rc) {
		free_dfs_info_array(*target_nodes, *num_of_nodes);
		*target_nodes = NULL;
		*num_of_nodes = 0;
	}
	return rc;
}
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863

struct cifs_aio_ctx *
cifs_aio_ctx_alloc(void)
{
	struct cifs_aio_ctx *ctx;

	ctx = kzalloc(sizeof(struct cifs_aio_ctx), GFP_KERNEL);
	if (!ctx)
		return NULL;

	INIT_LIST_HEAD(&ctx->list);
	mutex_init(&ctx->aio_mutex);
	init_completion(&ctx->done);
	kref_init(&ctx->refcount);
	return ctx;
}

void
cifs_aio_ctx_release(struct kref *refcount)
{
	struct cifs_aio_ctx *ctx = container_of(refcount,
					struct cifs_aio_ctx, refcount);

	cifsFileInfo_put(ctx->cfile);
	kvfree(ctx->bv);
	kfree(ctx);
}

#define CIFS_AIO_KMALLOC_LIMIT (1024 * 1024)

int
setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw)
{
	ssize_t rc;
	unsigned int cur_npages;
	unsigned int npages = 0;
	unsigned int i;
	size_t len;
	size_t count = iov_iter_count(iter);
	unsigned int saved_len;
	size_t start;
	unsigned int max_pages = iov_iter_npages(iter, INT_MAX);
	struct page **pages = NULL;
	struct bio_vec *bv = NULL;

	if (iter->type & ITER_KVEC) {
		memcpy(&ctx->iter, iter, sizeof(struct iov_iter));
		ctx->len = count;
		iov_iter_advance(iter, count);
		return 0;
	}

	if (max_pages * sizeof(struct bio_vec) <= CIFS_AIO_KMALLOC_LIMIT)
		bv = kmalloc_array(max_pages, sizeof(struct bio_vec),
				   GFP_KERNEL);

	if (!bv) {
		bv = vmalloc(max_pages * sizeof(struct bio_vec));
		if (!bv)
			return -ENOMEM;
	}

	if (max_pages * sizeof(struct page *) <= CIFS_AIO_KMALLOC_LIMIT)
		pages = kmalloc_array(max_pages, sizeof(struct page *),
				      GFP_KERNEL);

	if (!pages) {
		pages = vmalloc(max_pages * sizeof(struct page *));
		if (!bv) {
			kvfree(bv);
			return -ENOMEM;
		}
	}

	saved_len = count;

	while (count && npages < max_pages) {
		rc = iov_iter_get_pages(iter, pages, count, max_pages, &start);
		if (rc < 0) {
			cifs_dbg(VFS, "couldn't get user pages (rc=%zd)\n", rc);
			break;
		}

		if (rc > count) {
			cifs_dbg(VFS, "get pages rc=%zd more than %zu\n", rc,
				 count);
			break;
		}

		iov_iter_advance(iter, rc);
		count -= rc;
		rc += start;
		cur_npages = DIV_ROUND_UP(rc, PAGE_SIZE);

		if (npages + cur_npages > max_pages) {
			cifs_dbg(VFS, "out of vec array capacity (%u vs %u)\n",
				 npages + cur_npages, max_pages);
			break;
		}

		for (i = 0; i < cur_npages; i++) {
			len = rc > PAGE_SIZE ? PAGE_SIZE : rc;
			bv[npages + i].bv_page = pages[i];
			bv[npages + i].bv_offset = start;
			bv[npages + i].bv_len = len - start;
			rc -= len;
			start = 0;
		}

		npages += cur_npages;
	}

	kvfree(pages);
	ctx->bv = bv;
	ctx->len = saved_len - count;
	ctx->npages = npages;
	iov_iter_bvec(&ctx->iter, ITER_BVEC | rw, ctx->bv, npages, ctx->len);
	return 0;
}