Blame view

fs/cifs/smb2file.c 7.57 KB
f0df737ee   Pavel Shilovsky   CIFS: Add open/cl...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  /*
   *   fs/cifs/smb2file.c
   *
   *   Copyright (C) International Business Machines  Corp., 2002, 2011
   *   Author(s): Steve French (sfrench@us.ibm.com),
   *              Pavel Shilovsky ((pshilovsky@samba.org) 2012
   *
   *   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
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  #include <linux/fs.h>
  #include <linux/stat.h>
  #include <linux/slab.h>
  #include <linux/pagemap.h>
  #include <asm/div64.h>
  #include "cifsfs.h"
  #include "cifspdu.h"
  #include "cifsglob.h"
  #include "cifsproto.h"
  #include "cifs_debug.h"
  #include "cifs_fs_sb.h"
  #include "cifs_unicode.h"
  #include "fscache.h"
  #include "smb2proto.h"
  
  int
226730b4d   Pavel Shilovsky   CIFS: Introduce c...
38
39
  smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
  	       __u32 *oplock, FILE_ALL_INFO *buf)
f0df737ee   Pavel Shilovsky   CIFS: Add open/cl...
40
41
42
43
  {
  	int rc;
  	__le16 *smb2_path;
  	struct smb2_file_all_info *smb2_data = NULL;
b8c32dbb0   Pavel Shilovsky   CIFS: Request SMB...
44
  	__u8 smb2_oplock[17];
226730b4d   Pavel Shilovsky   CIFS: Introduce c...
45
  	struct cifs_fid *fid = oparms->fid;
592fafe64   Steve French   Add resilienthand...
46
  	struct network_resiliency_req nr_ioctl_req;
f0df737ee   Pavel Shilovsky   CIFS: Add open/cl...
47

226730b4d   Pavel Shilovsky   CIFS: Introduce c...
48
  	smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb);
f0df737ee   Pavel Shilovsky   CIFS: Add open/cl...
49
50
51
52
  	if (smb2_path == NULL) {
  		rc = -ENOMEM;
  		goto out;
  	}
1bbe4997b   Pavel Shilovsky   CIFS: Fix wrong f...
53
  	smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
f0df737ee   Pavel Shilovsky   CIFS: Add open/cl...
54
55
56
57
58
  			    GFP_KERNEL);
  	if (smb2_data == NULL) {
  		rc = -ENOMEM;
  		goto out;
  	}
226730b4d   Pavel Shilovsky   CIFS: Introduce c...
59
  	oparms->desired_access |= FILE_READ_ATTRIBUTES;
63eb3def3   Pavel Shilovsky   CIFS: Request dur...
60
  	*smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH;
b8c32dbb0   Pavel Shilovsky   CIFS: Request SMB...
61

226730b4d   Pavel Shilovsky   CIFS: Introduce c...
62
  	if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
b8c32dbb0   Pavel Shilovsky   CIFS: Request SMB...
63
  		memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);
f0df737ee   Pavel Shilovsky   CIFS: Add open/cl...
64

b42bf8882   Pavel Shilovsky   CIFS: Implement f...
65
  	rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data, NULL);
f0df737ee   Pavel Shilovsky   CIFS: Add open/cl...
66
67
  	if (rc)
  		goto out;
592fafe64   Steve French   Add resilienthand...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  
  	 if (oparms->tcon->use_resilient) {
  		nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */
  		nr_ioctl_req.Reserved = 0;
  		rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid,
  			fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY, true,
  			(char *)&nr_ioctl_req, sizeof(nr_ioctl_req),
  			NULL, NULL /* no return info */);
  		if (rc == -EOPNOTSUPP) {
  			cifs_dbg(VFS,
  			     "resiliency not supported by server, disabling
  ");
  			oparms->tcon->use_resilient = false;
  		} else if (rc)
  			cifs_dbg(FYI, "error %d setting resiliency
  ", rc);
  
  		rc = 0;
  	}
f0df737ee   Pavel Shilovsky   CIFS: Add open/cl...
87
88
  	if (buf) {
  		/* open response does not have IndexNumber field - get it */
226730b4d   Pavel Shilovsky   CIFS: Introduce c...
89
  		rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid,
f0df737ee   Pavel Shilovsky   CIFS: Add open/cl...
90
91
92
93
94
95
96
97
98
  				      fid->volatile_fid,
  				      &smb2_data->IndexNumber);
  		if (rc) {
  			/* let get_inode_info disable server inode numbers */
  			smb2_data->IndexNumber = 0;
  			rc = 0;
  		}
  		move_smb2_info_to_cifs(buf, smb2_data);
  	}
b8c32dbb0   Pavel Shilovsky   CIFS: Request SMB...
99
  	*oplock = *smb2_oplock;
f0df737ee   Pavel Shilovsky   CIFS: Add open/cl...
100
  out:
f0df737ee   Pavel Shilovsky   CIFS: Add open/cl...
101
102
103
104
  	kfree(smb2_data);
  	kfree(smb2_path);
  	return rc;
  }
f7ba7fe68   Pavel Shilovsky   CIFS: Add brlock ...
105
106
107
108
109
110
111
112
113
  
  int
  smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
  		  const unsigned int xid)
  {
  	int rc = 0, stored_rc;
  	unsigned int max_num, num = 0, max_buf;
  	struct smb2_lock_element *buf, *cur;
  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
2b0143b5c   David Howells   VFS: normal files...
114
  	struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
f7ba7fe68   Pavel Shilovsky   CIFS: Add brlock ...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  	struct cifsLockInfo *li, *tmp;
  	__u64 length = 1 + flock->fl_end - flock->fl_start;
  	struct list_head tmp_llist;
  
  	INIT_LIST_HEAD(&tmp_llist);
  
  	/*
  	 * Accessing maxBuf is racy with cifs_reconnect - need to store value
  	 * and check it for zero before using.
  	 */
  	max_buf = tcon->ses->server->maxBuf;
  	if (!max_buf)
  		return -EINVAL;
  
  	max_num = max_buf / sizeof(struct smb2_lock_element);
662e9b2b9   Fabian Frederick   fs/cifs/smb2file....
130
  	buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
f7ba7fe68   Pavel Shilovsky   CIFS: Add brlock ...
131
132
133
134
  	if (!buf)
  		return -ENOMEM;
  
  	cur = buf;
1b4b55a1d   Pavel Shilovsky   CIFS: Turn lock m...
135
  	down_write(&cinode->lock_sem);
f7ba7fe68   Pavel Shilovsky   CIFS: Add brlock ...
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  	list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) {
  		if (flock->fl_start > li->offset ||
  		    (flock->fl_start + length) <
  		    (li->offset + li->length))
  			continue;
  		if (current->tgid != li->pid)
  			continue;
  		if (cinode->can_cache_brlcks) {
  			/*
  			 * We can cache brlock requests - simply remove a lock
  			 * from the file's list.
  			 */
  			list_del(&li->llist);
  			cifs_del_lock_waiters(li);
  			kfree(li);
  			continue;
  		}
  		cur->Length = cpu_to_le64(li->length);
  		cur->Offset = cpu_to_le64(li->offset);
  		cur->Flags = cpu_to_le32(SMB2_LOCKFLAG_UNLOCK);
  		/*
  		 * We need to save a lock here to let us add it again to the
  		 * file's list if the unlock range request fails on the server.
  		 */
  		list_move(&li->llist, &tmp_llist);
  		if (++num == max_num) {
  			stored_rc = smb2_lockv(xid, tcon,
  					       cfile->fid.persistent_fid,
  					       cfile->fid.volatile_fid,
  					       current->tgid, num, buf);
  			if (stored_rc) {
  				/*
  				 * We failed on the unlock range request - add
  				 * all locks from the tmp list to the head of
  				 * the file's list.
  				 */
  				cifs_move_llist(&tmp_llist,
  						&cfile->llist->locks);
  				rc = stored_rc;
  			} else
  				/*
  				 * The unlock range request succeed - free the
  				 * tmp list.
  				 */
  				cifs_free_llist(&tmp_llist);
  			cur = buf;
  			num = 0;
  		} else
  			cur++;
  	}
  	if (num) {
  		stored_rc = smb2_lockv(xid, tcon, cfile->fid.persistent_fid,
  				       cfile->fid.volatile_fid, current->tgid,
  				       num, buf);
  		if (stored_rc) {
  			cifs_move_llist(&tmp_llist, &cfile->llist->locks);
  			rc = stored_rc;
  		} else
  			cifs_free_llist(&tmp_llist);
  	}
1b4b55a1d   Pavel Shilovsky   CIFS: Turn lock m...
196
  	up_write(&cinode->lock_sem);
f7ba7fe68   Pavel Shilovsky   CIFS: Add brlock ...
197
198
199
200
  
  	kfree(buf);
  	return rc;
  }
b140799a1   Pavel Shilovsky   CIFS: Use brlock ...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  
  static int
  smb2_push_mand_fdlocks(struct cifs_fid_locks *fdlocks, const unsigned int xid,
  		       struct smb2_lock_element *buf, unsigned int max_num)
  {
  	int rc = 0, stored_rc;
  	struct cifsFileInfo *cfile = fdlocks->cfile;
  	struct cifsLockInfo *li;
  	unsigned int num = 0;
  	struct smb2_lock_element *cur = buf;
  	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
  
  	list_for_each_entry(li, &fdlocks->locks, llist) {
  		cur->Length = cpu_to_le64(li->length);
  		cur->Offset = cpu_to_le64(li->offset);
  		cur->Flags = cpu_to_le32(li->type |
  						SMB2_LOCKFLAG_FAIL_IMMEDIATELY);
  		if (++num == max_num) {
  			stored_rc = smb2_lockv(xid, tcon,
  					       cfile->fid.persistent_fid,
  					       cfile->fid.volatile_fid,
  					       current->tgid, num, buf);
  			if (stored_rc)
  				rc = stored_rc;
  			cur = buf;
  			num = 0;
  		} else
  			cur++;
  	}
  	if (num) {
  		stored_rc = smb2_lockv(xid, tcon,
  				       cfile->fid.persistent_fid,
  				       cfile->fid.volatile_fid,
  				       current->tgid, num, buf);
  		if (stored_rc)
  			rc = stored_rc;
  	}
  
  	return rc;
  }
  
  int
  smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
  {
  	int rc = 0, stored_rc;
  	unsigned int xid;
  	unsigned int max_num, max_buf;
  	struct smb2_lock_element *buf;
2b0143b5c   David Howells   VFS: normal files...
249
  	struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
b140799a1   Pavel Shilovsky   CIFS: Use brlock ...
250
251
252
  	struct cifs_fid_locks *fdlocks;
  
  	xid = get_xid();
b140799a1   Pavel Shilovsky   CIFS: Use brlock ...
253
254
255
256
257
258
  
  	/*
  	 * Accessing maxBuf is racy with cifs_reconnect - need to store value
  	 * and check it for zero before using.
  	 */
  	max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
c954acc00   Pavel Shilovsky   CIFS: Fix a possi...
259
  	if (max_buf < sizeof(struct smb2_lock_element)) {
b140799a1   Pavel Shilovsky   CIFS: Use brlock ...
260
261
262
263
264
  		free_xid(xid);
  		return -EINVAL;
  	}
  
  	max_num = max_buf / sizeof(struct smb2_lock_element);
662e9b2b9   Fabian Frederick   fs/cifs/smb2file....
265
  	buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
b140799a1   Pavel Shilovsky   CIFS: Use brlock ...
266
  	if (!buf) {
b140799a1   Pavel Shilovsky   CIFS: Use brlock ...
267
268
269
270
271
272
273
274
275
  		free_xid(xid);
  		return -ENOMEM;
  	}
  
  	list_for_each_entry(fdlocks, &cinode->llist, llist) {
  		stored_rc = smb2_push_mand_fdlocks(fdlocks, xid, buf, max_num);
  		if (stored_rc)
  			rc = stored_rc;
  	}
b140799a1   Pavel Shilovsky   CIFS: Use brlock ...
276
  	kfree(buf);
b140799a1   Pavel Shilovsky   CIFS: Use brlock ...
277
278
279
  	free_xid(xid);
  	return rc;
  }