misc.c 24.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *   fs/cifs/misc.c
 *
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
#include "smb2pdu.h"
L
Linus Torvalds 已提交
34 35 36 37

extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;

S
Steve French 已提交
38 39 40 41
/* 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 已提交
42 43 44
   since the cifs fs was mounted */

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

	spin_lock(&GlobalMid_Lock);
	GlobalTotalActiveXid++;
51 52

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

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

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

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

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

	atomic_dec(&sesInfoAllocCount);
J
Jesper Juhl 已提交
98 99 100
	kfree(buf_to_free->serverOS);
	kfree(buf_to_free->serverDomain);
	kfree(buf_to_free->serverNOS);
101
	kzfree(buf_to_free->password);
102
	kfree(buf_to_free->user_name);
103
	kfree(buf_to_free->domainName);
104 105
	kzfree(buf_to_free->auth_key.response);
	kzfree(buf_to_free);
L
Linus Torvalds 已提交
106 107
}

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

void
131
tconInfoFree(struct cifs_tcon *buf_to_free)
L
Linus Torvalds 已提交
132 133
{
	if (buf_to_free == NULL) {
134
		cifs_dbg(FYI, "Null buffer passed to tconInfoFree\n");
L
Linus Torvalds 已提交
135 136 137
		return;
	}
	atomic_dec(&tconInfoAllocCount);
J
Jesper Juhl 已提交
138
	kfree(buf_to_free->nativeFileSystem);
139
	kzfree(buf_to_free->password);
140
	kfree(buf_to_free->crfid.fid);
L
Linus Torvalds 已提交
141 142 143 144 145 146 147
	kfree(buf_to_free);
}

struct smb_hdr *
cifs_buf_get(void)
{
	struct smb_hdr *ret_buf = NULL;
148 149 150 151
	/*
	 * SMB2 header is bigger than CIFS one - no problems to clean some
	 * more bytes for CIFS.
	 */
152
	size_t buf_size = sizeof(struct smb2_sync_hdr);
153

154 155 156 157 158 159
	/*
	 * 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.
	 */
160
	ret_buf = mempool_alloc(cifs_req_poolp, GFP_NOFS);
L
Linus Torvalds 已提交
161 162 163

	/* clear the first few header bytes */
	/* for most paths, more is cleared in header_assemble */
164 165
	memset(ret_buf, 0, buf_size + 3);
	atomic_inc(&bufAllocCount);
166
#ifdef CONFIG_CIFS_STATS2
167
	atomic_inc(&totBufAllocCount);
168
#endif /* CONFIG_CIFS_STATS2 */
L
Linus Torvalds 已提交
169 170 171 172 173 174 175 176

	return ret_buf;
}

void
cifs_buf_release(void *buf_to_free)
{
	if (buf_to_free == NULL) {
177
		/* cifs_dbg(FYI, "Null buffer passed to cifs_buf_release\n");*/
L
Linus Torvalds 已提交
178 179
		return;
	}
S
Steve French 已提交
180
	mempool_free(buf_to_free, cifs_req_poolp);
L
Linus Torvalds 已提交
181 182 183 184 185 186 187 188 189 190

	atomic_dec(&bufAllocCount);
	return;
}

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

S
Steve French 已提交
191 192 193
/* 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 已提交
194
   defaults to this and can not be bigger */
195
	ret_buf = mempool_alloc(cifs_sm_req_poolp, GFP_NOFS);
L
Linus Torvalds 已提交
196 197
	/* No need to clear memory here, cleared in header assemble */
	/*	memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
198
	atomic_inc(&smBufAllocCount);
199
#ifdef CONFIG_CIFS_STATS2
200
	atomic_inc(&totSmBufAllocCount);
201 202
#endif /* CONFIG_CIFS_STATS2 */

L
Linus Torvalds 已提交
203 204 205 206 207 208 209 210
	return ret_buf;
}

void
cifs_small_buf_release(void *buf_to_free)
{

	if (buf_to_free == NULL) {
211
		cifs_dbg(FYI, "Null buffer passed to cifs_small_buf_release\n");
L
Linus Torvalds 已提交
212 213
		return;
	}
S
Steve French 已提交
214
	mempool_free(buf_to_free, cifs_sm_req_poolp);
L
Linus Torvalds 已提交
215 216 217 218 219

	atomic_dec(&smBufAllocCount);
	return;
}

220 221 222 223 224 225 226 227 228
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);
}

229 230
/* 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 已提交
231 232
void
header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
233
		const struct cifs_tcon *treeCon, int word_count
L
Linus Torvalds 已提交
234 235 236 237
		/* length of fixed section (word count) in two byte units  */)
{
	char *temp = (char *) buffer;

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

240
	buffer->smb_buf_length = cpu_to_be32(
S
Steve French 已提交
241
	    (2 * word_count) + sizeof(struct smb_hdr) -
L
Linus Torvalds 已提交
242
	    4 /*  RFC 1001 length field does not count */  +
243
	    2 /* for bcc field itself */) ;
L
Linus Torvalds 已提交
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

	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;
259
			if (treeCon->ses->capabilities & CAP_STATUS32)
L
Linus Torvalds 已提交
260
				buffer->Flags2 |= SMBFLG2_ERR_STATUS;
261

262 263
			/* Uid is not converted */
			buffer->Uid = treeCon->ses->Suid;
264
			buffer->Mid = get_next_mid(treeCon->ses->server);
L
Linus Torvalds 已提交
265 266 267
		}
		if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
			buffer->Flags2 |= SMBFLG2_DFS;
268 269
		if (treeCon->nocase)
			buffer->Flags  |= SMBFLG_CASELESS;
270
		if ((treeCon->ses) && (treeCon->ses->server))
271
			if (treeCon->ses->server->sign)
L
Linus Torvalds 已提交
272 273 274 275 276 277 278 279
				buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
	}

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

280
static int
281
check_smb_hdr(struct smb_hdr *smb)
L
Linus Torvalds 已提交
282
{
283 284
	/* does it have the right SMB "signature" ? */
	if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) {
285 286
		cifs_dbg(VFS, "Bad protocol string signature header 0x%x\n",
			 *(unsigned int *)smb->Protocol);
287 288 289 290 291 292 293 294 295 296 297
		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;

298 299
	cifs_dbg(VFS, "Server sent request, not response. mid=%u\n",
		 get_mid(smb));
L
Linus Torvalds 已提交
300 301 302 303
	return 1;
}

int
304
checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server)
L
Linus Torvalds 已提交
305
{
306
	struct smb_hdr *smb = (struct smb_hdr *)buf;
J
Jeff Layton 已提交
307
	__u32 rfclen = be32_to_cpu(smb->smb_buf_length);
308
	__u32 clc_len;  /* calculated length */
309 310
	cifs_dbg(FYI, "checkSMB Length: 0x%x, smb_buf_length: 0x%x\n",
		 total_read, rfclen);
311

J
Jeff Layton 已提交
312 313 314
	/* 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 已提交
315
			    && (smb->Status.CifsError != 0)) {
J
Jeff Layton 已提交
316
			/* it's an error return */
317 318 319
			smb->WordCount = 0;
			/* some error cases do not return wct and bcc */
			return 0;
J
Jeff Layton 已提交
320
		} else if ((total_read == sizeof(struct smb_hdr) + 1) &&
321
				(smb->WordCount == 0)) {
S
Steve French 已提交
322
			char *tmp = (char *)smb;
323 324 325 326 327 328 329 330 331 332 333
			/* 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;
334
				return 0;
L
Linus Torvalds 已提交
335
			}
336
			cifs_dbg(VFS, "rcvd invalid byte count (bcc)\n");
337
		} else {
338
			cifs_dbg(VFS, "Length less than smb header size\n");
L
Linus Torvalds 已提交
339
		}
J
Jeff Layton 已提交
340
		return -EIO;
L
Linus Torvalds 已提交
341 342
	}

J
Jeff Layton 已提交
343
	/* otherwise, there is enough to get to the BCC */
344
	if (check_smb_hdr(smb))
J
Jeff Layton 已提交
345
		return -EIO;
346
	clc_len = smbCalcSize(smb, server);
347

J
Jeff Layton 已提交
348
	if (4 + rfclen != total_read) {
349 350
		cifs_dbg(VFS, "Length read does not match RFC1001 length %d\n",
			 rfclen);
J
Jeff Layton 已提交
351
		return -EIO;
352 353
	}

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

J
Jeff Layton 已提交
365
		if (4 + rfclen < clc_len) {
366
			cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u\n",
367
				 rfclen, mid);
J
Jeff Layton 已提交
368 369
			return -EIO;
		} else if (rfclen > clc_len + 512) {
370 371 372 373 374 375 376 377 378
			/*
			 * 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.
			 */
379
			cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u\n",
380
				 rfclen, mid);
J
Jeff Layton 已提交
381
			return -EIO;
382
		}
L
Linus Torvalds 已提交
383
	}
384
	return 0;
L
Linus Torvalds 已提交
385
}
386 387

bool
388
is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
S
Steve French 已提交
389
{
390
	struct smb_hdr *buf = (struct smb_hdr *)buffer;
S
Steve French 已提交
391
	struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
392
	struct list_head *tmp, *tmp1, *tmp2;
393 394
	struct cifs_ses *ses;
	struct cifs_tcon *tcon;
395
	struct cifsInodeInfo *pCifsInode;
L
Linus Torvalds 已提交
396 397
	struct cifsFileInfo *netfile;

398
	cifs_dbg(FYI, "Checking for oplock break or dnotify response\n");
399
	if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
L
Linus Torvalds 已提交
400
	   (pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
S
Steve French 已提交
401
		struct smb_com_transaction_change_notify_rsp *pSMBr =
L
Linus Torvalds 已提交
402
			(struct smb_com_transaction_change_notify_rsp *)buf;
S
Steve French 已提交
403
		struct file_notify_information *pnotify;
L
Linus Torvalds 已提交
404
		__u32 data_offset = 0;
405
		if (get_bcc(buf) > sizeof(struct file_notify_information)) {
L
Linus Torvalds 已提交
406 407
			data_offset = le32_to_cpu(pSMBr->DataOffset);

408 409
			pnotify = (struct file_notify_information *)
				((char *)&pSMBr->hdr.Protocol + data_offset);
410
			cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n",
411
				 pnotify->FileName, pnotify->Action);
S
Steve French 已提交
412
			/*   cifs_dump_mem("Rcvd notify Data: ",buf,
413
				sizeof(struct smb_hdr)+60); */
414
			return true;
L
Linus Torvalds 已提交
415
		}
416
		if (pSMBr->hdr.Status.CifsError) {
417
			cifs_dbg(FYI, "notify err 0x%x\n",
418
				 pSMBr->hdr.Status.CifsError);
419
			return true;
L
Linus Torvalds 已提交
420
		}
421
		return false;
S
Steve French 已提交
422
	}
423
	if (pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
424
		return false;
425
	if (pSMB->hdr.Flags & SMBFLG_RESPONSE) {
L
Linus Torvalds 已提交
426 427 428 429
		/* 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 已提交
430 431
		if ((NT_STATUS_INVALID_HANDLE) ==
		   le32_to_cpu(pSMB->hdr.Status.CifsError)) {
432
			cifs_dbg(FYI, "invalid handle on oplock break\n");
433
			return true;
S
Steve French 已提交
434
		} else if (ERRbadfid ==
L
Linus Torvalds 已提交
435
		   le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
436
			return true;
L
Linus Torvalds 已提交
437
		} else {
438
			return false; /* on valid oplock brk we get "request" */
L
Linus Torvalds 已提交
439 440
		}
	}
441
	if (pSMB->hdr.WordCount != 8)
442
		return false;
L
Linus Torvalds 已提交
443

444
	cifs_dbg(FYI, "oplock type 0x%x level 0x%x\n",
445
		 pSMB->LockType, pSMB->OplockLevel);
446
	if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
447
		return false;
L
Linus Torvalds 已提交
448 449

	/* look up tcon based on tid & uid */
450
	spin_lock(&cifs_tcp_ses_lock);
451
	list_for_each(tmp, &srv->smb_ses_list) {
452
		ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
453
		list_for_each(tmp1, &ses->tcon_list) {
454
			tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
455 456 457
			if (tcon->tid != buf->Tid)
				continue;

458
			cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
459
			spin_lock(&tcon->open_file_lock);
460 461
			list_for_each(tmp2, &tcon->openFileList) {
				netfile = list_entry(tmp2, struct cifsFileInfo,
462
						     tlist);
463
				if (pSMB->Fid != netfile->fid.netfid)
464 465
					continue;

466
				cifs_dbg(FYI, "file id match, oplock break\n");
467
				pCifsInode = CIFS_I(d_inode(netfile->dentry));
468

469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
				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);

485
				queue_work(cifsoplockd_wq,
486
					   &netfile->oplock_break);
487 488
				netfile->oplock_break_cancelled = false;

489
				spin_unlock(&tcon->open_file_lock);
490
				spin_unlock(&cifs_tcp_ses_lock);
491
				return true;
L
Linus Torvalds 已提交
492
			}
493
			spin_unlock(&tcon->open_file_lock);
494
			spin_unlock(&cifs_tcp_ses_lock);
495
			cifs_dbg(FYI, "No matching file for oplock break\n");
496
			return true;
L
Linus Torvalds 已提交
497 498
		}
	}
499
	spin_unlock(&cifs_tcp_ses_lock);
500
	cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n");
501
	return true;
L
Linus Torvalds 已提交
502 503 504
}

void
505
dump_smb(void *buf, int smb_buf_length)
L
Linus Torvalds 已提交
506 507 508 509
{
	if (traceSMB == 0)
		return;

510 511
	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, 8, 2, buf,
		       smb_buf_length, true);
L
Linus Torvalds 已提交
512
}
513

514 515 516 517
void
cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
{
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
518
		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
519 520
		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);
521 522
	}
}
523

524
void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
525
{
526
	oplock &= 0xF;
527

528
	if (oplock == OPLOCK_EXCLUSIVE) {
529
		cinode->oplock = CIFS_CACHE_WRITE_FLG | CIFS_CACHE_READ_FLG;
530 531
		cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
			 &cinode->vfs_inode);
532
	} else if (oplock == OPLOCK_READ) {
533
		cinode->oplock = CIFS_CACHE_READ_FLG;
534 535
		cifs_dbg(FYI, "Level II Oplock granted on inode %p\n",
			 &cinode->vfs_inode);
536 537
	} else
		cinode->oplock = 0;
538
}
539

540 541 542 543 544 545 546 547 548 549
/*
 * 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,
550
			 TASK_KILLABLE);
551 552 553 554 555 556 557 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
	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);
}

589 590 591 592
bool
backup_cred(struct cifs_sb_info *cifs_sb)
{
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) {
593
		if (uid_eq(cifs_sb->mnt_backupuid, current_fsuid()))
594 595 596 597 598 599 600 601 602
			return true;
	}
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) {
		if (in_group_p(cifs_sb->mnt_backupgid))
			return true;
	}

	return false;
}
603 604 605 606

void
cifs_del_pending_open(struct cifs_pending_open *open)
{
607
	spin_lock(&tlink_tcon(open->tlink)->open_file_lock);
608
	list_del(&open->olist);
609
	spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
}

void
cifs_add_pending_open_locked(struct cifs_fid *fid, struct tcon_link *tlink,
			     struct cifs_pending_open *open)
{
	memcpy(open->lease_key, fid->lease_key, SMB2_LEASE_KEY_SIZE);
	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)
{
627
	spin_lock(&tlink_tcon(tlink)->open_file_lock);
628
	cifs_add_pending_open_locked(fid, tlink, open);
629
	spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
630
}
631 632 633 634 635 636 637 638 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

/* 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;
}
736 737 738 739 740 741 742 743 744 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

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) {
793
		bv = vmalloc(array_size(max_pages, sizeof(struct bio_vec)));
794 795 796 797 798 799 800 801 802
		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) {
803
		pages = vmalloc(array_size(max_pages, sizeof(struct page *)));
804
		if (!pages) {
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
			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;
}
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908

/**
 * cifs_alloc_hash - allocate hash and hash context together
 *
 * The caller has to make sure @sdesc is initialized to either NULL or
 * a valid context. Both can be freed via cifs_free_hash().
 */
int
cifs_alloc_hash(const char *name,
		struct crypto_shash **shash, struct sdesc **sdesc)
{
	int rc = 0;
	size_t size;

	if (*sdesc != NULL)
		return 0;

	*shash = crypto_alloc_shash(name, 0, 0);
	if (IS_ERR(*shash)) {
		cifs_dbg(VFS, "could not allocate crypto %s\n", name);
		rc = PTR_ERR(*shash);
		*shash = NULL;
		*sdesc = NULL;
		return rc;
	}

	size = sizeof(struct shash_desc) + crypto_shash_descsize(*shash);
	*sdesc = kmalloc(size, GFP_KERNEL);
	if (*sdesc == NULL) {
		cifs_dbg(VFS, "no memory left to allocate crypto %s\n", name);
		crypto_free_shash(*shash);
		*shash = NULL;
		return -ENOMEM;
	}

	(*sdesc)->shash.tfm = *shash;
	(*sdesc)->shash.flags = 0x0;
	return 0;
}

/**
 * cifs_free_hash - free hash and hash context together
 *
 * Freeing a NULL hash or context is safe.
 */
void
cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc)
{
	kfree(*sdesc);
	*sdesc = NULL;
	if (*shash)
		crypto_free_shash(*shash);
	*shash = NULL;
}
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925

/**
 * rqst_page_get_length - obtain the length and offset for a page in smb_rqst
 * Input: rqst - a smb_rqst, page - a page index for rqst
 * Output: *len - the length for this page, *offset - the offset for this page
 */
void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
				unsigned int *len, unsigned int *offset)
{
	*len = rqst->rq_pagesz;
	*offset = (page == 0) ? rqst->rq_offset : 0;

	if (rqst->rq_npages == 1 || page == rqst->rq_npages-1)
		*len = rqst->rq_tailsz;
	else if (page == 0)
		*len = rqst->rq_pagesz - rqst->rq_offset;
}
反馈
建议
客服 返回
顶部