Blame view

fs/cifs/misc.c 30.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   *   fs/cifs/misc.c
   *
ad7a2926b   Steve French   [CIFS] reduce che...
4
   *   Copyright (C) International Business Machines  Corp., 2002,2008
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
fb8c4b14d   Steve French   [CIFS] whitespace...
19
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
24
   */
  
  #include <linux/slab.h>
  #include <linux/ctype.h>
  #include <linux/mempool.h>
ccf7f4088   Pavel Shilovsky   CIFS: Add asynchr...
25
  #include <linux/vmalloc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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"
6c91d362f   Steve French   [PATCH] cifs: fin...
32
  #include "cifs_unicode.h"
3792c1732   Pavel Shilovsky   CIFS: Respect SMB...
33
  #include "smb2pdu.h"
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
34
  #include "cifsfs.h"
e4af35fa5   Paulo Alcantara   cifs: handle host...
35
36
37
  #ifdef CONFIG_CIFS_DFS_UPCALL
  #include "dns_resolve.h"
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
  
  extern mempool_t *cifs_sm_req_poolp;
  extern mempool_t *cifs_req_poolp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41

fb8c4b14d   Steve French   [CIFS] whitespace...
42
43
44
45
  /* 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
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
     since the cifs fs was mounted */
  
  unsigned int
6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
49
  _get_xid(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
53
54
  {
  	unsigned int xid;
  
  	spin_lock(&GlobalMid_Lock);
  	GlobalTotalActiveXid++;
50c2f7538   Steve French   [CIFS] whitespace...
55
56
  
  	/* keep high water mark for number of simultaneous ops in filesystem */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  	if (GlobalTotalActiveXid > GlobalMaxActiveXid)
50c2f7538   Steve French   [CIFS] whitespace...
58
  		GlobalMaxActiveXid = GlobalTotalActiveXid;
790fe579f   Steve French   [CIFS] more white...
59
  	if (GlobalTotalActiveXid > 65000)
f96637be0   Joe Perches   [CIFS] cifs: Rena...
60
61
  		cifs_dbg(FYI, "warning: more than 65000 requests active
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
  	xid = GlobalCurrentXid++;
  	spin_unlock(&GlobalMid_Lock);
  	return xid;
  }
  
  void
6d5786a34   Pavel Shilovsky   CIFS: Rename Get/...
68
  _free_xid(unsigned int xid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
  {
  	spin_lock(&GlobalMid_Lock);
790fe579f   Steve French   [CIFS] more white...
71
  	/* if (GlobalTotalActiveXid == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
  		BUG(); */
  	GlobalTotalActiveXid--;
  	spin_unlock(&GlobalMid_Lock);
  }
96daf2b09   Steve French   [CIFS] Rename thr...
76
  struct cifs_ses *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
  sesInfoAlloc(void)
  {
96daf2b09   Steve French   [CIFS] Rename thr...
79
  	struct cifs_ses *ret_buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80

96daf2b09   Steve French   [CIFS] Rename thr...
81
  	ret_buf = kzalloc(sizeof(struct cifs_ses), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  	if (ret_buf) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
  		atomic_inc(&sesInfoAllocCount);
  		ret_buf->status = CifsNew;
14fbf50d6   Jeff Layton   cifs: reinstate s...
85
86
  		++ret_buf->ses_count;
  		INIT_LIST_HEAD(&ret_buf->smb_ses_list);
f1987b44f   Jeff Layton   cifs: reinstate s...
87
  		INIT_LIST_HEAD(&ret_buf->tcon_list);
d7b619cf5   Steve French   [CIFS] pSesInfo->...
88
  		mutex_init(&ret_buf->session_mutex);
b6f0dd5d7   Aurelien Aptel   CIFS: add iface i...
89
  		spin_lock_init(&ret_buf->iface_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
  	}
  	return ret_buf;
  }
  
  void
96daf2b09   Steve French   [CIFS] Rename thr...
95
  sesInfoFree(struct cifs_ses *buf_to_free)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
  {
  	if (buf_to_free == NULL) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
98
99
  		cifs_dbg(FYI, "Null buffer passed to sesInfoFree
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  	atomic_dec(&sesInfoAllocCount);
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
103
104
105
  	kfree(buf_to_free->serverOS);
  	kfree(buf_to_free->serverDomain);
  	kfree(buf_to_free->serverNOS);
453431a54   Waiman Long   mm, treewide: ren...
106
  	kfree_sensitive(buf_to_free->password);
8727c8a85   Steve French   Allow user names ...
107
  	kfree(buf_to_free->user_name);
3979877e5   Steve French   [CIFS] Support fo...
108
  	kfree(buf_to_free->domainName);
453431a54   Waiman Long   mm, treewide: ren...
109
  	kfree_sensitive(buf_to_free->auth_key.response);
b6f0dd5d7   Aurelien Aptel   CIFS: add iface i...
110
  	kfree(buf_to_free->iface_list);
453431a54   Waiman Long   mm, treewide: ren...
111
  	kfree_sensitive(buf_to_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  }
96daf2b09   Steve French   [CIFS] Rename thr...
113
  struct cifs_tcon *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
  tconInfoAlloc(void)
  {
96daf2b09   Steve French   [CIFS] Rename thr...
116
  	struct cifs_tcon *ret_buf;
0544b324e   Joe Perches   cifs: check kzall...
117
118
119
120
121
122
123
124
  
  	ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL);
  	if (!ret_buf)
  		return NULL;
  	ret_buf->crfid.fid = kzalloc(sizeof(*ret_buf->crfid.fid), GFP_KERNEL);
  	if (!ret_buf->crfid.fid) {
  		kfree(ret_buf);
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  	}
0544b324e   Joe Perches   cifs: check kzall...
126
127
128
129
130
131
132
133
134
135
136
  
  	atomic_inc(&tconInfoAllocCount);
  	ret_buf->tidStatus = CifsNew;
  	++ret_buf->tc_count;
  	INIT_LIST_HEAD(&ret_buf->openFileList);
  	INIT_LIST_HEAD(&ret_buf->tcon_list);
  	spin_lock_init(&ret_buf->open_file_lock);
  	mutex_init(&ret_buf->crfid.fid_mutex);
  	spin_lock_init(&ret_buf->stat_lock);
  	atomic_set(&ret_buf->num_local_opens, 0);
  	atomic_set(&ret_buf->num_remote_opens, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
  	return ret_buf;
  }
  
  void
96daf2b09   Steve French   [CIFS] Rename thr...
141
  tconInfoFree(struct cifs_tcon *buf_to_free)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
  {
  	if (buf_to_free == NULL) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
144
145
  		cifs_dbg(FYI, "Null buffer passed to tconInfoFree
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  	atomic_dec(&tconInfoAllocCount);
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
149
  	kfree(buf_to_free->nativeFileSystem);
453431a54   Waiman Long   mm, treewide: ren...
150
  	kfree_sensitive(buf_to_free->password);
a93864d93   Ronnie Sahlberg   cifs: add lease t...
151
  	kfree(buf_to_free->crfid.fid);
4a367dc04   Paulo Alcantara   cifs: Add support...
152
153
154
  #ifdef CONFIG_CIFS_DFS_UPCALL
  	kfree(buf_to_free->dfs_path);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
159
160
161
  	kfree(buf_to_free);
  }
  
  struct smb_hdr *
  cifs_buf_get(void)
  {
  	struct smb_hdr *ret_buf = NULL;
3792c1732   Pavel Shilovsky   CIFS: Respect SMB...
162
163
164
165
  	/*
  	 * SMB2 header is bigger than CIFS one - no problems to clean some
  	 * more bytes for CIFS.
  	 */
49f466bdb   Ronnie Sahlberg   cifs: remove stru...
166
  	size_t buf_size = sizeof(struct smb2_sync_hdr);
2a38e1205   Steve French   [SMB3] Remove ifd...
167

3792c1732   Pavel Shilovsky   CIFS: Respect SMB...
168
169
170
171
172
173
  	/*
  	 * 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.
  	 */
232087cb7   Pekka Enberg   cifs: don't use G...
174
  	ret_buf = mempool_alloc(cifs_req_poolp, GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
  
  	/* clear the first few header bytes */
  	/* for most paths, more is cleared in header_assemble */
a6f74e80f   NeilBrown   cifs: don't check...
178
179
  	memset(ret_buf, 0, buf_size + 3);
  	atomic_inc(&bufAllocCount);
4498eed50   Steve French   [CIFS] Add extend...
180
  #ifdef CONFIG_CIFS_STATS2
a6f74e80f   NeilBrown   cifs: don't check...
181
  	atomic_inc(&totBufAllocCount);
4498eed50   Steve French   [CIFS] Add extend...
182
  #endif /* CONFIG_CIFS_STATS2 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
185
186
187
188
189
  
  	return ret_buf;
  }
  
  void
  cifs_buf_release(void *buf_to_free)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
  	if (buf_to_free == NULL) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
191
192
  		/* cifs_dbg(FYI, "Null buffer passed to cifs_buf_release
  ");*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  		return;
  	}
fb8c4b14d   Steve French   [CIFS] whitespace...
195
  	mempool_free(buf_to_free, cifs_req_poolp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
200
201
202
203
204
  
  	atomic_dec(&bufAllocCount);
  	return;
  }
  
  struct smb_hdr *
  cifs_small_buf_get(void)
  {
  	struct smb_hdr *ret_buf = NULL;
fb8c4b14d   Steve French   [CIFS] whitespace...
205
206
207
  /* 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
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
     defaults to this and can not be bigger */
232087cb7   Pekka Enberg   cifs: don't use G...
209
  	ret_buf = mempool_alloc(cifs_sm_req_poolp, GFP_NOFS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
  	/* No need to clear memory here, cleared in header assemble */
  	/*	memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
a6f74e80f   NeilBrown   cifs: don't check...
212
  	atomic_inc(&smBufAllocCount);
4498eed50   Steve French   [CIFS] Add extend...
213
  #ifdef CONFIG_CIFS_STATS2
a6f74e80f   NeilBrown   cifs: don't check...
214
  	atomic_inc(&totSmBufAllocCount);
4498eed50   Steve French   [CIFS] Add extend...
215
  #endif /* CONFIG_CIFS_STATS2 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
218
219
220
221
222
223
  	return ret_buf;
  }
  
  void
  cifs_small_buf_release(void *buf_to_free)
  {
  
  	if (buf_to_free == NULL) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
224
225
  		cifs_dbg(FYI, "Null buffer passed to cifs_small_buf_release
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
  		return;
  	}
fb8c4b14d   Steve French   [CIFS] whitespace...
228
  	mempool_free(buf_to_free, cifs_sm_req_poolp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
  
  	atomic_dec(&smBufAllocCount);
  	return;
  }
6d81ed1ec   Sachin Prabhu   cifs: replace cod...
233
234
235
236
237
238
239
240
  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);
  }
1982c344f   Steve French   [CIFS] Ensure tha...
241
242
  /* NB: MID can not be set if treeCon not passed in, in that
     case it is responsbility of caller to set the mid */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
  void
  header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
96daf2b09   Steve French   [CIFS] Rename thr...
245
  		const struct cifs_tcon *treeCon, int word_count
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
  		/* length of fixed section (word count) in two byte units  */)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
  	char *temp = (char *) buffer;
fb8c4b14d   Steve French   [CIFS] whitespace...
249
  	memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250

be8e3b004   Steve French   consistently use ...
251
  	buffer->smb_buf_length = cpu_to_be32(
630f3f0c4   Steve French   [CIFS] acl suppor...
252
  	    (2 * word_count) + sizeof(struct smb_hdr) -
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  	    4 /*  RFC 1001 length field does not count */  +
be8e3b004   Steve French   consistently use ...
254
  	    2 /* for bcc field itself */) ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
258
259
260
261
262
263
264
  
  	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));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
268
269
  	if (treeCon) {
  		buffer->Tid = treeCon->tid;
  		if (treeCon->ses) {
  			if (treeCon->ses->capabilities & CAP_UNICODE)
  				buffer->Flags2 |= SMBFLG2_UNICODE;
ad7a2926b   Steve French   [CIFS] reduce che...
270
  			if (treeCon->ses->capabilities & CAP_STATUS32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  				buffer->Flags2 |= SMBFLG2_ERR_STATUS;
ad7a2926b   Steve French   [CIFS] reduce che...
272

1982c344f   Steve French   [CIFS] Ensure tha...
273
274
  			/* Uid is not converted */
  			buffer->Uid = treeCon->ses->Suid;
882573606   Pavel Shilovsky   CIFS: Move get_ne...
275
  			buffer->Mid = get_next_mid(treeCon->ses->server);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
  		}
  		if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
  			buffer->Flags2 |= SMBFLG2_DFS;
d3485d37c   Steve French   [CIFS] Finish cif...
279
280
  		if (treeCon->nocase)
  			buffer->Flags  |= SMBFLG_CASELESS;
790fe579f   Steve French   [CIFS] more white...
281
  		if ((treeCon->ses) && (treeCon->ses->server))
38d77c50b   Jeff Layton   cifs: track the e...
282
  			if (treeCon->ses->server->sign)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
286
287
288
289
  				buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
  	}
  
  /*  endian conversion of flags is now done just before sending */
  	buffer->WordCount = (char) word_count;
  	return;
  }
2cd646a2d   Steve French   [CIFS] Remove sta...
290
  static int
944d6f1a5   Tim Gardner   cifs: Remove redu...
291
  check_smb_hdr(struct smb_hdr *smb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  {
68abaffa6   Jeff Layton   cifs: simplify SM...
293
294
  	/* does it have the right SMB "signature" ? */
  	if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
295
296
297
  		cifs_dbg(VFS, "Bad protocol string signature header 0x%x
  ",
  			 *(unsigned int *)smb->Protocol);
68abaffa6   Jeff Layton   cifs: simplify SM...
298
299
  		return 1;
  	}
68abaffa6   Jeff Layton   cifs: simplify SM...
300
301
302
303
304
305
306
  	/* 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;
3d378d3fd   Tim Gardner   cifs: Make big en...
307
308
309
  	cifs_dbg(VFS, "Server sent request, not response. mid=%u
  ",
  		 get_mid(smb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
  	return 1;
  }
  
  int
373512ec5   Steve French   Prepare for encry...
314
  checkSMB(char *buf, unsigned int total_read, struct TCP_Server_Info *server)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  {
d4e4854fd   Pavel Shilovsky   CIFS: Separate pr...
316
  	struct smb_hdr *smb = (struct smb_hdr *)buf;
376b43f41   Jeff Layton   cifs: clean up ch...
317
  	__u32 rfclen = be32_to_cpu(smb->smb_buf_length);
190fdeb84   Steve French   [CIFS] Fix byte r...
318
  	__u32 clc_len;  /* calculated length */
f96637be0   Joe Perches   [CIFS] cifs: Rena...
319
320
321
  	cifs_dbg(FYI, "checkSMB Length: 0x%x, smb_buf_length: 0x%x
  ",
  		 total_read, rfclen);
d103e164b   Steve French   [CIFS] Workaround...
322

376b43f41   Jeff Layton   cifs: clean up ch...
323
324
325
  	/* 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)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
  			    && (smb->Status.CifsError != 0)) {
376b43f41   Jeff Layton   cifs: clean up ch...
327
  			/* it's an error return */
d103e164b   Steve French   [CIFS] Workaround...
328
329
330
  			smb->WordCount = 0;
  			/* some error cases do not return wct and bcc */
  			return 0;
376b43f41   Jeff Layton   cifs: clean up ch...
331
  		} else if ((total_read == sizeof(struct smb_hdr) + 1) &&
d103e164b   Steve French   [CIFS] Workaround...
332
  				(smb->WordCount == 0)) {
fb8c4b14d   Steve French   [CIFS] whitespace...
333
  			char *tmp = (char *)smb;
d103e164b   Steve French   [CIFS] Workaround...
334
335
336
337
338
339
340
341
342
343
344
  			/* 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;
46c79a645   Steve French   [CIFS] Move noisy...
345
  				return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  			}
f96637be0   Joe Perches   [CIFS] cifs: Rena...
347
348
  			cifs_dbg(VFS, "rcvd invalid byte count (bcc)
  ");
d103e164b   Steve French   [CIFS] Workaround...
349
  		} else {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
350
351
  			cifs_dbg(VFS, "Length less than smb header size
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  		}
376b43f41   Jeff Layton   cifs: clean up ch...
353
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  	}
376b43f41   Jeff Layton   cifs: clean up ch...
355
  	/* otherwise, there is enough to get to the BCC */
944d6f1a5   Tim Gardner   cifs: Remove redu...
356
  	if (check_smb_hdr(smb))
376b43f41   Jeff Layton   cifs: clean up ch...
357
  		return -EIO;
9ec672bd1   Ronnie Sahlberg   cifs: update calc...
358
  	clc_len = smbCalcSize(smb, server);
184ed2110   Steve French   [CIFS] Fix large ...
359

376b43f41   Jeff Layton   cifs: clean up ch...
360
  	if (4 + rfclen != total_read) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
361
362
363
  		cifs_dbg(VFS, "Length read does not match RFC1001 length %d
  ",
  			 rfclen);
376b43f41   Jeff Layton   cifs: clean up ch...
364
  		return -EIO;
184ed2110   Steve French   [CIFS] Fix large ...
365
  	}
376b43f41   Jeff Layton   cifs: clean up ch...
366
  	if (4 + rfclen != clc_len) {
3d378d3fd   Tim Gardner   cifs: Make big en...
367
  		__u16 mid = get_mid(smb);
184ed2110   Steve French   [CIFS] Fix large ...
368
  		/* check if bcc wrapped around for large read responses */
376b43f41   Jeff Layton   cifs: clean up ch...
369
  		if ((rfclen > 64 * 1024) && (rfclen > clc_len)) {
184ed2110   Steve French   [CIFS] Fix large ...
370
  			/* check if lengths match mod 64K */
376b43f41   Jeff Layton   cifs: clean up ch...
371
  			if (((4 + rfclen) & 0xFFFF) == (clc_len & 0xFFFF))
fb8c4b14d   Steve French   [CIFS] whitespace...
372
  				return 0; /* bcc wrapped */
184ed2110   Steve French   [CIFS] Fix large ...
373
  		}
f96637be0   Joe Perches   [CIFS] cifs: Rena...
374
375
  		cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=%u
  ",
3d378d3fd   Tim Gardner   cifs: Make big en...
376
  			 clc_len, 4 + rfclen, mid);
6284644e8   Jeff Layton   cifs: fix length ...
377

376b43f41   Jeff Layton   cifs: clean up ch...
378
  		if (4 + rfclen < clc_len) {
f96637be0   Joe Perches   [CIFS] cifs: Rena...
379
380
  			cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=%u
  ",
3d378d3fd   Tim Gardner   cifs: Make big en...
381
  				 rfclen, mid);
376b43f41   Jeff Layton   cifs: clean up ch...
382
383
  			return -EIO;
  		} else if (rfclen > clc_len + 512) {
6284644e8   Jeff Layton   cifs: fix length ...
384
385
386
387
388
389
390
391
392
  			/*
  			 * 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.
  			 */
f96637be0   Joe Perches   [CIFS] cifs: Rena...
393
394
  			cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for mid=%u
  ",
3d378d3fd   Tim Gardner   cifs: Make big en...
395
  				 rfclen, mid);
376b43f41   Jeff Layton   cifs: clean up ch...
396
  			return -EIO;
46c79a645   Steve French   [CIFS] Move noisy...
397
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  	}
209624388   Steve French   [CIFS] Add suppor...
399
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
  }
4b18f2a9c   Steve French   [CIFS] convert us...
401
402
  
  bool
d4e4854fd   Pavel Shilovsky   CIFS: Separate pr...
403
  is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
fb8c4b14d   Steve French   [CIFS] whitespace...
404
  {
d4e4854fd   Pavel Shilovsky   CIFS: Separate pr...
405
  	struct smb_hdr *buf = (struct smb_hdr *)buffer;
fb8c4b14d   Steve French   [CIFS] whitespace...
406
  	struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
f1987b44f   Jeff Layton   cifs: reinstate s...
407
  	struct list_head *tmp, *tmp1, *tmp2;
96daf2b09   Steve French   [CIFS] Rename thr...
408
409
  	struct cifs_ses *ses;
  	struct cifs_tcon *tcon;
f1987b44f   Jeff Layton   cifs: reinstate s...
410
  	struct cifsInodeInfo *pCifsInode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  	struct cifsFileInfo *netfile;
f96637be0   Joe Perches   [CIFS] cifs: Rena...
412
413
  	cifs_dbg(FYI, "Checking for oplock break or dnotify response
  ");
790fe579f   Steve French   [CIFS] more white...
414
  	if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  	   (pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
fb8c4b14d   Steve French   [CIFS] whitespace...
416
  		struct smb_com_transaction_change_notify_rsp *pSMBr =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
  			(struct smb_com_transaction_change_notify_rsp *)buf;
fb8c4b14d   Steve French   [CIFS] whitespace...
418
  		struct file_notify_information *pnotify;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
  		__u32 data_offset = 0;
097f5863b   Dan Carpenter   cifs: read overfl...
420
  		size_t len = srv->total_read - sizeof(pSMBr->hdr.smb_buf_length);
820a803ff   Jeff Layton   cifs: keep BCC in...
421
  		if (get_bcc(buf) > sizeof(struct file_notify_information)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
  			data_offset = le32_to_cpu(pSMBr->DataOffset);
097f5863b   Dan Carpenter   cifs: read overfl...
423
424
  			if (data_offset >
  			    len - sizeof(struct file_notify_information)) {
a0a3036b8   Joe Perches   cifs: Standardize...
425
426
  				cifs_dbg(FYI, "Invalid data_offset %u
  ",
097f5863b   Dan Carpenter   cifs: read overfl...
427
428
429
  					 data_offset);
  				return true;
  			}
3979877e5   Steve French   [CIFS] Support fo...
430
431
  			pnotify = (struct file_notify_information *)
  				((char *)&pSMBr->hdr.Protocol + data_offset);
f96637be0   Joe Perches   [CIFS] cifs: Rena...
432
433
  			cifs_dbg(FYI, "dnotify on %s Action: 0x%x
  ",
b6b38f704   Joe Perches   [CIFS] Neaten cER...
434
  				 pnotify->FileName, pnotify->Action);
fb8c4b14d   Steve French   [CIFS] whitespace...
435
  			/*   cifs_dump_mem("Rcvd notify Data: ",buf,
3979877e5   Steve French   [CIFS] Support fo...
436
  				sizeof(struct smb_hdr)+60); */
4b18f2a9c   Steve French   [CIFS] convert us...
437
  			return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
  		}
790fe579f   Steve French   [CIFS] more white...
439
  		if (pSMBr->hdr.Status.CifsError) {
59b04c5df   Steve French   [CIFS] Fix incorr...
440
441
  			cifs_dbg(FYI, "notify err 0x%x
  ",
f96637be0   Joe Perches   [CIFS] cifs: Rena...
442
  				 pSMBr->hdr.Status.CifsError);
4b18f2a9c   Steve French   [CIFS] convert us...
443
  			return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
  		}
4b18f2a9c   Steve French   [CIFS] convert us...
445
  		return false;
fb8c4b14d   Steve French   [CIFS] whitespace...
446
  	}
790fe579f   Steve French   [CIFS] more white...
447
  	if (pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
4b18f2a9c   Steve French   [CIFS] convert us...
448
  		return false;
790fe579f   Steve French   [CIFS] more white...
449
  	if (pSMB->hdr.Flags & SMBFLG_RESPONSE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
452
453
  		/* 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 */
fb8c4b14d   Steve French   [CIFS] whitespace...
454
455
  		if ((NT_STATUS_INVALID_HANDLE) ==
  		   le32_to_cpu(pSMB->hdr.Status.CifsError)) {
a0a3036b8   Joe Perches   cifs: Standardize...
456
457
  			cifs_dbg(FYI, "Invalid handle on oplock break
  ");
4b18f2a9c   Steve French   [CIFS] convert us...
458
  			return true;
fb8c4b14d   Steve French   [CIFS] whitespace...
459
  		} else if (ERRbadfid ==
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
  		   le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
4b18f2a9c   Steve French   [CIFS] convert us...
461
  			return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
  		} else {
4b18f2a9c   Steve French   [CIFS] convert us...
463
  			return false; /* on valid oplock brk we get "request" */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
465
  		}
  	}
790fe579f   Steve French   [CIFS] more white...
466
  	if (pSMB->hdr.WordCount != 8)
4b18f2a9c   Steve French   [CIFS] convert us...
467
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468

59b04c5df   Steve French   [CIFS] Fix incorr...
469
470
  	cifs_dbg(FYI, "oplock type 0x%x level 0x%x
  ",
b6b38f704   Joe Perches   [CIFS] Neaten cER...
471
  		 pSMB->LockType, pSMB->OplockLevel);
790fe579f   Steve French   [CIFS] more white...
472
  	if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
4b18f2a9c   Steve French   [CIFS] convert us...
473
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
  
  	/* look up tcon based on tid & uid */
3f9bcca78   Suresh Jayaraman   cifs: convert cif...
476
  	spin_lock(&cifs_tcp_ses_lock);
f1987b44f   Jeff Layton   cifs: reinstate s...
477
  	list_for_each(tmp, &srv->smb_ses_list) {
96daf2b09   Steve French   [CIFS] Rename thr...
478
  		ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
f1987b44f   Jeff Layton   cifs: reinstate s...
479
  		list_for_each(tmp1, &ses->tcon_list) {
96daf2b09   Steve French   [CIFS] Rename thr...
480
  			tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
f1987b44f   Jeff Layton   cifs: reinstate s...
481
482
  			if (tcon->tid != buf->Tid)
  				continue;
44c581866   Pavel Shilovsky   CIFS: Move clear/...
483
  			cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
3afca265b   Steve French   Clarify locking o...
484
  			spin_lock(&tcon->open_file_lock);
f1987b44f   Jeff Layton   cifs: reinstate s...
485
486
  			list_for_each(tmp2, &tcon->openFileList) {
  				netfile = list_entry(tmp2, struct cifsFileInfo,
57337e42f   Steve French   [PATCH] cifs: han...
487
  						     tlist);
4b4de76e3   Pavel Shilovsky   CIFS: Replace net...
488
  				if (pSMB->Fid != netfile->fid.netfid)
f1987b44f   Jeff Layton   cifs: reinstate s...
489
  					continue;
f96637be0   Joe Perches   [CIFS] cifs: Rena...
490
491
  				cifs_dbg(FYI, "file id match, oplock break
  ");
2b0143b5c   David Howells   VFS: normal files...
492
  				pCifsInode = CIFS_I(d_inode(netfile->dentry));
9b6469724   Tejun Heo   cifs: use workque...
493

c11f1df50   Sachin Prabhu   cifs: Wait for wr...
494
495
  				set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK,
  					&pCifsInode->flags);
9bd454083   Pavel Shilovsky   CIFS: Properly pr...
496
497
  				netfile->oplock_epoch = 0;
  				netfile->oplock_level = pSMB->OplockLevel;
9b6469724   Tejun Heo   cifs: use workque...
498
  				netfile->oplock_break_cancelled = false;
9bd454083   Pavel Shilovsky   CIFS: Properly pr...
499
  				cifs_queue_oplock_break(netfile);
9b6469724   Tejun Heo   cifs: use workque...
500

3afca265b   Steve French   Clarify locking o...
501
  				spin_unlock(&tcon->open_file_lock);
3f9bcca78   Suresh Jayaraman   cifs: convert cif...
502
  				spin_unlock(&cifs_tcp_ses_lock);
f1987b44f   Jeff Layton   cifs: reinstate s...
503
  				return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
  			}
3afca265b   Steve French   Clarify locking o...
505
  			spin_unlock(&tcon->open_file_lock);
3f9bcca78   Suresh Jayaraman   cifs: convert cif...
506
  			spin_unlock(&cifs_tcp_ses_lock);
f96637be0   Joe Perches   [CIFS] cifs: Rena...
507
508
  			cifs_dbg(FYI, "No matching file for oplock break
  ");
4b18f2a9c   Steve French   [CIFS] convert us...
509
  			return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
  		}
  	}
3f9bcca78   Suresh Jayaraman   cifs: convert cif...
512
  	spin_unlock(&cifs_tcp_ses_lock);
f96637be0   Joe Perches   [CIFS] cifs: Rena...
513
514
  	cifs_dbg(FYI, "Can not process oplock break for non-existent connection
  ");
4b18f2a9c   Steve French   [CIFS] convert us...
515
  	return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
518
  }
  
  void
792af7b05   Pavel Shilovsky   CIFS: Separate pr...
519
  dump_smb(void *buf, int smb_buf_length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
  	if (traceSMB == 0)
  		return;
55d83e0db   Andy Shevchenko   cifs: convert to ...
523
524
  	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, 8, 2, buf,
  		       smb_buf_length, true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
  }
6a0b48245   Steve French   [PATCH] cifs: Add...
526

ec06aedd4   Jeff Layton   cifs: clean up ha...
527
528
529
530
  void
  cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
  {
  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
5fc7fcd05   Aurelien Aptel   cifs: auto disabl...
531
532
533
534
  		struct cifs_tcon *tcon = NULL;
  
  		if (cifs_sb->master_tlink)
  			tcon = cifs_sb_master_tcon(cifs_sb);
f534dc994   Suresh Jayaraman   cifs: clear serve...
535
  		cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
29fbeb7a9   Paulo Alcantara (SUSE)   cifs: Properly ha...
536
  		cifs_sb->mnt_cifs_serverino_autodisabled = true;
a0a3036b8   Joe Perches   cifs: Standardize...
537
538
  		cifs_dbg(VFS, "Autodisabling the use of server inode numbers on %s
  ",
5fc7fcd05   Aurelien Aptel   cifs: auto disabl...
539
  			 tcon ? tcon->treeName : "new server");
a0a3036b8   Joe Perches   cifs: Standardize...
540
541
  		cifs_dbg(VFS, "The server doesn't seem to support them properly or the files might be on different servers (DFS)
  ");
5fc7fcd05   Aurelien Aptel   cifs: auto disabl...
542
543
  		cifs_dbg(VFS, "Hardlinks will not be recognized on this mount. Consider mounting with the \"noserverino\" option to silence this message.
  ");
ec06aedd4   Jeff Layton   cifs: clean up ha...
544
545
  	}
  }
e66673e39   Pavel Shilovsky   CIFS: Add cifs_se...
546

c67236281   Pavel Shilovsky   cifs: make cifs_s...
547
  void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
e66673e39   Pavel Shilovsky   CIFS: Add cifs_se...
548
  {
c67236281   Pavel Shilovsky   cifs: make cifs_s...
549
  	oplock &= 0xF;
e66673e39   Pavel Shilovsky   CIFS: Add cifs_se...
550

c67236281   Pavel Shilovsky   cifs: make cifs_s...
551
  	if (oplock == OPLOCK_EXCLUSIVE) {
18cceb6a7   Pavel Shilovsky   CIFS: Replace cli...
552
  		cinode->oplock = CIFS_CACHE_WRITE_FLG | CIFS_CACHE_READ_FLG;
f96637be0   Joe Perches   [CIFS] cifs: Rena...
553
554
555
  		cifs_dbg(FYI, "Exclusive Oplock granted on inode %p
  ",
  			 &cinode->vfs_inode);
c67236281   Pavel Shilovsky   cifs: make cifs_s...
556
  	} else if (oplock == OPLOCK_READ) {
18cceb6a7   Pavel Shilovsky   CIFS: Replace cli...
557
  		cinode->oplock = CIFS_CACHE_READ_FLG;
f96637be0   Joe Perches   [CIFS] cifs: Rena...
558
559
560
  		cifs_dbg(FYI, "Level II Oplock granted on inode %p
  ",
  			 &cinode->vfs_inode);
18cceb6a7   Pavel Shilovsky   CIFS: Replace cli...
561
562
  	} else
  		cinode->oplock = 0;
e66673e39   Pavel Shilovsky   CIFS: Add cifs_se...
563
  }
3d3ea8e64   Shirish Pargaonkar   cifs: Add mount o...
564

c11f1df50   Sachin Prabhu   cifs: Wait for wr...
565
566
567
568
569
570
571
572
573
574
  /*
   * 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,
743162013   NeilBrown   sched: Remove pro...
575
  			 TASK_KILLABLE);
c11f1df50   Sachin Prabhu   cifs: Wait for wr...
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
  	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);
  }
b98749cac   Aurelien Aptel   CIFS: keep FileIn...
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
  /**
   * cifs_queue_oplock_break - queue the oplock break handler for cfile
   *
   * This function is called from the demultiplex thread when it
   * receives an oplock break for @cfile.
   *
   * Assumes the tcon->open_file_lock is held.
   * Assumes cfile->file_info_lock is NOT held.
   */
  void cifs_queue_oplock_break(struct cifsFileInfo *cfile)
  {
  	/*
  	 * Bump the handle refcount now while we hold the
  	 * open_file_lock to enforce the validity of it for the oplock
  	 * break handler. The matching put is done at the end of the
  	 * handler.
  	 */
  	cifsFileInfo_get(cfile);
  
  	queue_work(cifsoplockd_wq, &cfile->oplock_break);
  }
c11f1df50   Sachin Prabhu   cifs: Wait for wr...
628
629
630
631
632
  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);
  }
3d3ea8e64   Shirish Pargaonkar   cifs: Add mount o...
633
634
635
636
  bool
  backup_cred(struct cifs_sb_info *cifs_sb)
  {
  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) {
1f68233c5   Eric W. Biederman   cifs: Convert str...
637
  		if (uid_eq(cifs_sb->mnt_backupuid, current_fsuid()))
3d3ea8e64   Shirish Pargaonkar   cifs: Add mount o...
638
639
640
641
642
643
644
645
646
  			return true;
  	}
  	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) {
  		if (in_group_p(cifs_sb->mnt_backupgid))
  			return true;
  	}
  
  	return false;
  }
233839b1d   Pavel Shilovsky   CIFS: Fix fast le...
647
648
649
650
  
  void
  cifs_del_pending_open(struct cifs_pending_open *open)
  {
3afca265b   Steve French   Clarify locking o...
651
  	spin_lock(&tlink_tcon(open->tlink)->open_file_lock);
233839b1d   Pavel Shilovsky   CIFS: Fix fast le...
652
  	list_del(&open->olist);
3afca265b   Steve French   Clarify locking o...
653
  	spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
233839b1d   Pavel Shilovsky   CIFS: Fix fast le...
654
655
656
657
658
659
  }
  
  void
  cifs_add_pending_open_locked(struct cifs_fid *fid, struct tcon_link *tlink,
  			     struct cifs_pending_open *open)
  {
233839b1d   Pavel Shilovsky   CIFS: Fix fast le...
660
  	memcpy(open->lease_key, fid->lease_key, SMB2_LEASE_KEY_SIZE);
233839b1d   Pavel Shilovsky   CIFS: Fix fast le...
661
662
663
664
665
666
667
668
669
670
  	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)
  {
3afca265b   Steve French   Clarify locking o...
671
  	spin_lock(&tlink_tcon(tlink)->open_file_lock);
233839b1d   Pavel Shilovsky   CIFS: Fix fast le...
672
  	cifs_add_pending_open_locked(fid, tlink, open);
3afca265b   Steve French   Clarify locking o...
673
  	spin_unlock(&tlink_tcon(open->tlink)->open_file_lock);
233839b1d   Pavel Shilovsky   CIFS: Fix fast le...
674
  }
4ecce920e   Aurelien Aptel   CIFS: move DFS re...
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
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
  
  /* 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
  ",
  			 *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
  ",
  			 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 ...
  ",
  		 *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;
  		}
e7b602f43   Paulo Alcantara   cifs: Save TTL va...
771
  		node->ttl = le32_to_cpu(ref->TimeToLive);
4ecce920e   Aurelien Aptel   CIFS: move DFS re...
772
773
774
775
776
777
778
779
780
781
782
  		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;
  }
ccf7f4088   Pavel Shilovsky   CIFS: Add asynchr...
783
784
785
786
787
  
  struct cifs_aio_ctx *
  cifs_aio_ctx_alloc(void)
  {
  	struct cifs_aio_ctx *ctx;
13f5938d8   Jérôme Glisse   cifs: fix page re...
788
789
790
791
792
  	/*
  	 * Must use kzalloc to initialize ctx->bv to NULL and ctx->direct_io
  	 * to false so that we know when we have to unreference pages within
  	 * cifs_aio_ctx_release()
  	 */
ccf7f4088   Pavel Shilovsky   CIFS: Add asynchr...
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
  	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);
13f5938d8   Jérôme Glisse   cifs: fix page re...
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
  
  	/*
  	 * ctx->bv is only set if setup_aio_ctx_iter() was call successfuly
  	 * which means that iov_iter_get_pages() was a success and thus that
  	 * we have taken reference on pages.
  	 */
  	if (ctx->bv) {
  		unsigned i;
  
  		for (i = 0; i < ctx->npages; i++) {
  			if (ctx->should_dirty)
  				set_page_dirty(ctx->bv[i].bv_page);
  			put_page(ctx->bv[i].bv_page);
  		}
  		kvfree(ctx->bv);
  	}
ccf7f4088   Pavel Shilovsky   CIFS: Add asynchr...
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
  	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;
00e237074   David Howells   iov_iter: Use acc...
846
  	if (iov_iter_is_kvec(iter)) {
bf1028a41   Gustavo A. R. Silva   cifs: misc: Use a...
847
  		memcpy(&ctx->iter, iter, sizeof(*iter));
ccf7f4088   Pavel Shilovsky   CIFS: Add asynchr...
848
849
850
851
  		ctx->len = count;
  		iov_iter_advance(iter, count);
  		return 0;
  	}
bf1028a41   Gustavo A. R. Silva   cifs: misc: Use a...
852
853
  	if (array_size(max_pages, sizeof(*bv)) <= CIFS_AIO_KMALLOC_LIMIT)
  		bv = kmalloc_array(max_pages, sizeof(*bv), GFP_KERNEL);
ccf7f4088   Pavel Shilovsky   CIFS: Add asynchr...
854
855
  
  	if (!bv) {
bf1028a41   Gustavo A. R. Silva   cifs: misc: Use a...
856
  		bv = vmalloc(array_size(max_pages, sizeof(*bv)));
ccf7f4088   Pavel Shilovsky   CIFS: Add asynchr...
857
858
859
  		if (!bv)
  			return -ENOMEM;
  	}
bf1028a41   Gustavo A. R. Silva   cifs: misc: Use a...
860
861
  	if (array_size(max_pages, sizeof(*pages)) <= CIFS_AIO_KMALLOC_LIMIT)
  		pages = kmalloc_array(max_pages, sizeof(*pages), GFP_KERNEL);
ccf7f4088   Pavel Shilovsky   CIFS: Add asynchr...
862
863
  
  	if (!pages) {
bf1028a41   Gustavo A. R. Silva   cifs: misc: Use a...
864
  		pages = vmalloc(array_size(max_pages, sizeof(*pages)));
ecf3411a1   Colin Ian King   CIFS: check if pa...
865
  		if (!pages) {
ccf7f4088   Pavel Shilovsky   CIFS: Add asynchr...
866
867
868
869
870
871
872
873
874
875
  			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) {
a0a3036b8   Joe Perches   cifs: Standardize...
876
877
  			cifs_dbg(VFS, "Couldn't get user pages (rc=%zd)
  ", rc);
ccf7f4088   Pavel Shilovsky   CIFS: Add asynchr...
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
909
910
911
912
913
914
915
  			break;
  		}
  
  		if (rc > count) {
  			cifs_dbg(VFS, "get pages rc=%zd more than %zu
  ", 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)
  ",
  				 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;
aa563d7bc   David Howells   iov_iter: Separat...
916
  	iov_iter_bvec(&ctx->iter, rw, ctx->bv, npages, ctx->len);
ccf7f4088   Pavel Shilovsky   CIFS: Add asynchr...
917
918
  	return 0;
  }
82fb82be0   Aurelien Aptel   CIFS: refactor cr...
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
  
  /**
   * 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)) {
a0a3036b8   Joe Perches   cifs: Standardize...
938
939
  		cifs_dbg(VFS, "Could not allocate crypto %s
  ", name);
82fb82be0   Aurelien Aptel   CIFS: refactor cr...
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
  		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
  ", name);
  		crypto_free_shash(*shash);
  		*shash = NULL;
  		return -ENOMEM;
  	}
  
  	(*sdesc)->shash.tfm = *shash;
82fb82be0   Aurelien Aptel   CIFS: refactor cr...
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
  	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;
  }
7b7f2bdf8   Long Li   CIFS: Introduce h...
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
  
  /**
   * 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;
  }
a3a53b760   Paulo Alcantara   cifs: Add support...
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
  
  void extract_unc_hostname(const char *unc, const char **h, size_t *len)
  {
  	const char *end;
  
  	/* skip initial slashes */
  	while (*unc && (*unc == '\\' || *unc == '/'))
  		unc++;
  
  	end = unc;
  
  	while (*end && !(*end == '\\' || *end == '/'))
  		end++;
  
  	*h = unc;
  	*len = end - unc;
  }
340625e61   Ronnie Sahlberg   cifs: replace var...
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
  
  /**
   * copy_path_name - copy src path to dst, possibly truncating
   *
   * returns number of bytes written (including trailing nul)
   */
  int copy_path_name(char *dst, const char *src)
  {
  	int name_len;
  
  	/*
  	 * PATH_MAX includes nul, so if strlen(src) >= PATH_MAX it
  	 * will truncate and strlen(dst) will be PATH_MAX-1
  	 */
  	name_len = strscpy(dst, src, PATH_MAX);
  	if (WARN_ON_ONCE(name_len < 0))
  		name_len = PATH_MAX-1;
  
  	/* we count the trailing nul */
  	name_len++;
  	return name_len;
  }
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1030
1031
  
  struct super_cb_data {
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1032
  	void *data;
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1033
1034
  	struct super_block *sb;
  };
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1035
  static void tcp_super_cb(struct super_block *sb, void *arg)
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1036
  {
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1037
1038
  	struct super_cb_data *sd = arg;
  	struct TCP_Server_Info *server = sd->data;
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1039
1040
  	struct cifs_sb_info *cifs_sb;
  	struct cifs_tcon *tcon;
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1041
  	if (sd->sb)
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1042
1043
1044
1045
  		return;
  
  	cifs_sb = CIFS_SB(sb);
  	tcon = cifs_sb_master_tcon(cifs_sb);
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1046
1047
  	if (tcon->ses->server == server)
  		sd->sb = sb;
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1048
  }
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1049
1050
  static struct super_block *__cifs_get_super(void (*f)(struct super_block *, void *),
  					    void *data)
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1051
  {
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1052
1053
  	struct super_cb_data sd = {
  		.data = data,
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1054
1055
  		.sb = NULL,
  	};
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1056
  	iterate_supers_type(&cifs_fs_type, f, &sd);
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1057

3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1058
1059
  	if (!sd.sb)
  		return ERR_PTR(-EINVAL);
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1060
1061
1062
1063
1064
  	/*
  	 * Grab an active reference in order to prevent automounts (DFS links)
  	 * of expiring and then freeing up our cifs superblock pointer while
  	 * we're doing failover.
  	 */
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1065
1066
  	cifs_sb_active(sd.sb);
  	return sd.sb;
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1067
  }
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1068
  static void __cifs_put_super(struct super_block *sb)
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1069
1070
1071
1072
  {
  	if (!IS_ERR_OR_NULL(sb))
  		cifs_sb_deactive(sb);
  }
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
  struct super_block *cifs_get_tcp_super(struct TCP_Server_Info *server)
  {
  	return __cifs_get_super(tcp_super_cb, server);
  }
  
  void cifs_put_tcp_super(struct super_block *sb)
  {
  	__cifs_put_super(sb);
  }
  
  #ifdef CONFIG_CIFS_DFS_UPCALL
e4af35fa5   Paulo Alcantara   cifs: handle host...
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
  int match_target_ip(struct TCP_Server_Info *server,
  		    const char *share, size_t share_len,
  		    bool *result)
  {
  	int rc;
  	char *target, *tip = NULL;
  	struct sockaddr tipaddr;
  
  	*result = false;
  
  	target = kzalloc(share_len + 3, GFP_KERNEL);
  	if (!target) {
  		rc = -ENOMEM;
  		goto out;
  	}
  
  	scnprintf(target, share_len + 3, "\\\\%.*s", (int)share_len, share);
  
  	cifs_dbg(FYI, "%s: target name: %s
  ", __func__, target + 2);
  
  	rc = dns_resolve_server_name_to_ip(target, &tip);
  	if (rc < 0)
  		goto out;
  
  	cifs_dbg(FYI, "%s: target ip: %s
  ", __func__, tip);
  
  	if (!cifs_convert_address(&tipaddr, tip, strlen(tip))) {
  		cifs_dbg(VFS, "%s: failed to convert target ip address
  ",
  			 __func__);
  		rc = -EINVAL;
  		goto out;
  	}
  
  	*result = cifs_match_ipaddr((struct sockaddr *)&server->dstaddr,
  				    &tipaddr);
  	cifs_dbg(FYI, "%s: ip addresses match: %u
  ", __func__, *result);
  	rc = 0;
  
  out:
  	kfree(target);
  	kfree(tip);
  
  	return rc;
  }
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
  static void tcon_super_cb(struct super_block *sb, void *arg)
  {
  	struct super_cb_data *sd = arg;
  	struct cifs_tcon *tcon = sd->data;
  	struct cifs_sb_info *cifs_sb;
  
  	if (sd->sb)
  		return;
  
  	cifs_sb = CIFS_SB(sb);
  	if (tcon->dfs_path && cifs_sb->origin_fullpath &&
  	    !strcasecmp(tcon->dfs_path, cifs_sb->origin_fullpath))
  		sd->sb = sb;
  }
  
  static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon)
  {
  	return __cifs_get_super(tcon_super_cb, tcon);
  }
  
  static inline void cifs_put_tcon_super(struct super_block *sb)
  {
  	__cifs_put_super(sb);
  }
  #else
  static inline struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon)
  {
  	return ERR_PTR(-EOPNOTSUPP);
  }
  
  static inline void cifs_put_tcon_super(struct super_block *sb)
  {
  }
  #endif
7548e1da8   Paulo Alcantara   cifs: handle RESP...
1166
  int update_super_prepath(struct cifs_tcon *tcon, char *prefix)
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1167
1168
1169
1170
  {
  	struct super_block *sb;
  	struct cifs_sb_info *cifs_sb;
  	int rc = 0;
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1171
  	sb = cifs_get_tcon_super(tcon);
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1172
1173
1174
1175
1176
1177
  	if (IS_ERR(sb))
  		return PTR_ERR(sb);
  
  	cifs_sb = CIFS_SB(sb);
  
  	kfree(cifs_sb->prepath);
7548e1da8   Paulo Alcantara   cifs: handle RESP...
1178
1179
  	if (prefix && *prefix) {
  		cifs_sb->prepath = kstrndup(prefix, strlen(prefix), GFP_ATOMIC);
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
  		if (!cifs_sb->prepath) {
  			rc = -ENOMEM;
  			goto out;
  		}
  
  		convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
  	} else
  		cifs_sb->prepath = NULL;
  
  	cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
  
  out:
3786f4bdd   Paulo Alcantara   cifs: ensure corr...
1192
  	cifs_put_tcon_super(sb);
bacd704a9   Paulo Alcantara (SUSE)   cifs: handle pref...
1193
1194
  	return rc;
  }