blob: 71e6aed4b382442525df0571d47329c0ddf8db90 [file] [log] [blame]
Pavel Shilovskyf0df7372012-09-18 16:20:26 -07001/*
2 * fs/cifs/smb2file.c
3 *
4 * Copyright (C) International Business Machines Corp., 2002, 2011
5 * Author(s): Steve French (sfrench@us.ibm.com),
6 * Pavel Shilovsky ((pshilovsky@samba.org) 2012
7 *
8 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
16 * the GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22#include <linux/fs.h>
23#include <linux/stat.h>
24#include <linux/slab.h>
25#include <linux/pagemap.h>
26#include <asm/div64.h>
27#include "cifsfs.h"
28#include "cifspdu.h"
29#include "cifsglob.h"
30#include "cifsproto.h"
31#include "cifs_debug.h"
32#include "cifs_fs_sb.h"
33#include "cifs_unicode.h"
34#include "fscache.h"
35#include "smb2proto.h"
36
Pavel Shilovsky2e44b282012-09-18 16:20:33 -070037void
38smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
39{
40 oplock &= 0xFF;
Pavel Shilovsky0822f512012-09-19 06:22:45 -070041 if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
42 return;
Pavel Shilovsky2e44b282012-09-18 16:20:33 -070043 if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
44 cinode->clientCanCacheAll = true;
45 cinode->clientCanCacheRead = true;
46 cFYI(1, "Exclusive Oplock granted on inode %p",
47 &cinode->vfs_inode);
48 } else if (oplock == SMB2_OPLOCK_LEVEL_II) {
49 cinode->clientCanCacheAll = false;
50 cinode->clientCanCacheRead = true;
51 cFYI(1, "Level II Oplock granted on inode %p",
52 &cinode->vfs_inode);
53 } else {
54 cinode->clientCanCacheAll = false;
55 cinode->clientCanCacheRead = false;
56 }
57}
58
Pavel Shilovskyf0df7372012-09-18 16:20:26 -070059int
60smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
61 int disposition, int desired_access, int create_options,
62 struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
63 struct cifs_sb_info *cifs_sb)
64{
65 int rc;
66 __le16 *smb2_path;
67 struct smb2_file_all_info *smb2_data = NULL;
Pavel Shilovskyb8c32db2012-09-19 06:22:44 -070068 __u8 smb2_oplock[17];
Pavel Shilovskyf0df7372012-09-18 16:20:26 -070069
70 smb2_path = cifs_convert_path_to_utf16(path, cifs_sb);
71 if (smb2_path == NULL) {
72 rc = -ENOMEM;
73 goto out;
74 }
75
76 smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
77 GFP_KERNEL);
78 if (smb2_data == NULL) {
79 rc = -ENOMEM;
80 goto out;
81 }
82
83 desired_access |= FILE_READ_ATTRIBUTES;
Pavel Shilovskyb8c32db2012-09-19 06:22:44 -070084 *smb2_oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
85
86 if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
87 memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);
Pavel Shilovskyf0df7372012-09-18 16:20:26 -070088
89 rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
90 &fid->volatile_fid, desired_access, disposition,
Pavel Shilovskyb8c32db2012-09-19 06:22:44 -070091 0, 0, smb2_oplock, smb2_data);
Pavel Shilovskyf0df7372012-09-18 16:20:26 -070092 if (rc)
93 goto out;
94
95 if (buf) {
96 /* open response does not have IndexNumber field - get it */
97 rc = SMB2_get_srv_num(xid, tcon, fid->persistent_fid,
98 fid->volatile_fid,
99 &smb2_data->IndexNumber);
100 if (rc) {
101 /* let get_inode_info disable server inode numbers */
102 smb2_data->IndexNumber = 0;
103 rc = 0;
104 }
105 move_smb2_info_to_cifs(buf, smb2_data);
106 }
107
Pavel Shilovskyb8c32db2012-09-19 06:22:44 -0700108 *oplock = *smb2_oplock;
Pavel Shilovskyf0df7372012-09-18 16:20:26 -0700109out:
Pavel Shilovskyf0df7372012-09-18 16:20:26 -0700110 kfree(smb2_data);
111 kfree(smb2_path);
112 return rc;
113}
Pavel Shilovskyf7ba7fe2012-09-19 06:22:43 -0700114
115int
116smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
117 const unsigned int xid)
118{
119 int rc = 0, stored_rc;
120 unsigned int max_num, num = 0, max_buf;
121 struct smb2_lock_element *buf, *cur;
122 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
123 struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
124 struct cifsLockInfo *li, *tmp;
125 __u64 length = 1 + flock->fl_end - flock->fl_start;
126 struct list_head tmp_llist;
127
128 INIT_LIST_HEAD(&tmp_llist);
129
130 /*
131 * Accessing maxBuf is racy with cifs_reconnect - need to store value
132 * and check it for zero before using.
133 */
134 max_buf = tcon->ses->server->maxBuf;
135 if (!max_buf)
136 return -EINVAL;
137
138 max_num = max_buf / sizeof(struct smb2_lock_element);
139 buf = kzalloc(max_num * sizeof(struct smb2_lock_element), GFP_KERNEL);
140 if (!buf)
141 return -ENOMEM;
142
143 cur = buf;
144
Pavel Shilovsky1b4b55a2012-09-19 06:22:44 -0700145 down_write(&cinode->lock_sem);
Pavel Shilovskyf7ba7fe2012-09-19 06:22:43 -0700146 list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) {
147 if (flock->fl_start > li->offset ||
148 (flock->fl_start + length) <
149 (li->offset + li->length))
150 continue;
151 if (current->tgid != li->pid)
152 continue;
153 if (cinode->can_cache_brlcks) {
154 /*
155 * We can cache brlock requests - simply remove a lock
156 * from the file's list.
157 */
158 list_del(&li->llist);
159 cifs_del_lock_waiters(li);
160 kfree(li);
161 continue;
162 }
163 cur->Length = cpu_to_le64(li->length);
164 cur->Offset = cpu_to_le64(li->offset);
165 cur->Flags = cpu_to_le32(SMB2_LOCKFLAG_UNLOCK);
166 /*
167 * We need to save a lock here to let us add it again to the
168 * file's list if the unlock range request fails on the server.
169 */
170 list_move(&li->llist, &tmp_llist);
171 if (++num == max_num) {
172 stored_rc = smb2_lockv(xid, tcon,
173 cfile->fid.persistent_fid,
174 cfile->fid.volatile_fid,
175 current->tgid, num, buf);
176 if (stored_rc) {
177 /*
178 * We failed on the unlock range request - add
179 * all locks from the tmp list to the head of
180 * the file's list.
181 */
182 cifs_move_llist(&tmp_llist,
183 &cfile->llist->locks);
184 rc = stored_rc;
185 } else
186 /*
187 * The unlock range request succeed - free the
188 * tmp list.
189 */
190 cifs_free_llist(&tmp_llist);
191 cur = buf;
192 num = 0;
193 } else
194 cur++;
195 }
196 if (num) {
197 stored_rc = smb2_lockv(xid, tcon, cfile->fid.persistent_fid,
198 cfile->fid.volatile_fid, current->tgid,
199 num, buf);
200 if (stored_rc) {
201 cifs_move_llist(&tmp_llist, &cfile->llist->locks);
202 rc = stored_rc;
203 } else
204 cifs_free_llist(&tmp_llist);
205 }
Pavel Shilovsky1b4b55a2012-09-19 06:22:44 -0700206 up_write(&cinode->lock_sem);
Pavel Shilovskyf7ba7fe2012-09-19 06:22:43 -0700207
208 kfree(buf);
209 return rc;
210}
Pavel Shilovskyb1407992012-09-19 06:22:44 -0700211
212static int
213smb2_push_mand_fdlocks(struct cifs_fid_locks *fdlocks, const unsigned int xid,
214 struct smb2_lock_element *buf, unsigned int max_num)
215{
216 int rc = 0, stored_rc;
217 struct cifsFileInfo *cfile = fdlocks->cfile;
218 struct cifsLockInfo *li;
219 unsigned int num = 0;
220 struct smb2_lock_element *cur = buf;
221 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
222
223 list_for_each_entry(li, &fdlocks->locks, llist) {
224 cur->Length = cpu_to_le64(li->length);
225 cur->Offset = cpu_to_le64(li->offset);
226 cur->Flags = cpu_to_le32(li->type |
227 SMB2_LOCKFLAG_FAIL_IMMEDIATELY);
228 if (++num == max_num) {
229 stored_rc = smb2_lockv(xid, tcon,
230 cfile->fid.persistent_fid,
231 cfile->fid.volatile_fid,
232 current->tgid, num, buf);
233 if (stored_rc)
234 rc = stored_rc;
235 cur = buf;
236 num = 0;
237 } else
238 cur++;
239 }
240 if (num) {
241 stored_rc = smb2_lockv(xid, tcon,
242 cfile->fid.persistent_fid,
243 cfile->fid.volatile_fid,
244 current->tgid, num, buf);
245 if (stored_rc)
246 rc = stored_rc;
247 }
248
249 return rc;
250}
251
252int
253smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
254{
255 int rc = 0, stored_rc;
256 unsigned int xid;
257 unsigned int max_num, max_buf;
258 struct smb2_lock_element *buf;
259 struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
260 struct cifs_fid_locks *fdlocks;
261
262 xid = get_xid();
Pavel Shilovskyb1407992012-09-19 06:22:44 -0700263
264 /*
265 * Accessing maxBuf is racy with cifs_reconnect - need to store value
266 * and check it for zero before using.
267 */
268 max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
269 if (!max_buf) {
Pavel Shilovskyb1407992012-09-19 06:22:44 -0700270 free_xid(xid);
271 return -EINVAL;
272 }
273
274 max_num = max_buf / sizeof(struct smb2_lock_element);
275 buf = kzalloc(max_num * sizeof(struct smb2_lock_element), GFP_KERNEL);
276 if (!buf) {
Pavel Shilovskyb1407992012-09-19 06:22:44 -0700277 free_xid(xid);
278 return -ENOMEM;
279 }
280
281 list_for_each_entry(fdlocks, &cinode->llist, llist) {
282 stored_rc = smb2_push_mand_fdlocks(fdlocks, xid, buf, max_num);
283 if (stored_rc)
284 rc = stored_rc;
285 }
286
Pavel Shilovskyb1407992012-09-19 06:22:44 -0700287 kfree(buf);
Pavel Shilovskyb1407992012-09-19 06:22:44 -0700288 free_xid(xid);
289 return rc;
290}