1 /*
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 
37 int
smb2_open_file(const unsigned int xid,struct cifs_open_parms * oparms,__u32 * oplock,FILE_ALL_INFO * buf)38 smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
39 	       __u32 *oplock, FILE_ALL_INFO *buf)
40 {
41 	int rc;
42 	__le16 *smb2_path;
43 	struct smb2_file_all_info *smb2_data = NULL;
44 	__u8 smb2_oplock[17];
45 	struct cifs_fid *fid = oparms->fid;
46 
47 	smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb);
48 	if (smb2_path == NULL) {
49 		rc = -ENOMEM;
50 		goto out;
51 	}
52 
53 	smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
54 			    GFP_KERNEL);
55 	if (smb2_data == NULL) {
56 		rc = -ENOMEM;
57 		goto out;
58 	}
59 
60 	oparms->desired_access |= FILE_READ_ATTRIBUTES;
61 	*smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH;
62 
63 	if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
64 		memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);
65 
66 	rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data, NULL);
67 	if (rc)
68 		goto out;
69 
70 	if (buf) {
71 		/* open response does not have IndexNumber field - get it */
72 		rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid,
73 				      fid->volatile_fid,
74 				      &smb2_data->IndexNumber);
75 		if (rc) {
76 			/* let get_inode_info disable server inode numbers */
77 			smb2_data->IndexNumber = 0;
78 			rc = 0;
79 		}
80 		move_smb2_info_to_cifs(buf, smb2_data);
81 	}
82 
83 	*oplock = *smb2_oplock;
84 out:
85 	kfree(smb2_data);
86 	kfree(smb2_path);
87 	return rc;
88 }
89 
90 int
smb2_unlock_range(struct cifsFileInfo * cfile,struct file_lock * flock,const unsigned int xid)91 smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
92 		  const unsigned int xid)
93 {
94 	int rc = 0, stored_rc;
95 	unsigned int max_num, num = 0, max_buf;
96 	struct smb2_lock_element *buf, *cur;
97 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
98 	struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
99 	struct cifsLockInfo *li, *tmp;
100 	__u64 length = 1 + flock->fl_end - flock->fl_start;
101 	struct list_head tmp_llist;
102 
103 	INIT_LIST_HEAD(&tmp_llist);
104 
105 	/*
106 	 * Accessing maxBuf is racy with cifs_reconnect - need to store value
107 	 * and check it for zero before using.
108 	 */
109 	max_buf = tcon->ses->server->maxBuf;
110 	if (!max_buf)
111 		return -EINVAL;
112 
113 	max_num = max_buf / sizeof(struct smb2_lock_element);
114 	buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
115 	if (!buf)
116 		return -ENOMEM;
117 
118 	cur = buf;
119 
120 	down_write(&cinode->lock_sem);
121 	list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) {
122 		if (flock->fl_start > li->offset ||
123 		    (flock->fl_start + length) <
124 		    (li->offset + li->length))
125 			continue;
126 		if (current->tgid != li->pid)
127 			continue;
128 		if (cinode->can_cache_brlcks) {
129 			/*
130 			 * We can cache brlock requests - simply remove a lock
131 			 * from the file's list.
132 			 */
133 			list_del(&li->llist);
134 			cifs_del_lock_waiters(li);
135 			kfree(li);
136 			continue;
137 		}
138 		cur->Length = cpu_to_le64(li->length);
139 		cur->Offset = cpu_to_le64(li->offset);
140 		cur->Flags = cpu_to_le32(SMB2_LOCKFLAG_UNLOCK);
141 		/*
142 		 * We need to save a lock here to let us add it again to the
143 		 * file's list if the unlock range request fails on the server.
144 		 */
145 		list_move(&li->llist, &tmp_llist);
146 		if (++num == max_num) {
147 			stored_rc = smb2_lockv(xid, tcon,
148 					       cfile->fid.persistent_fid,
149 					       cfile->fid.volatile_fid,
150 					       current->tgid, num, buf);
151 			if (stored_rc) {
152 				/*
153 				 * We failed on the unlock range request - add
154 				 * all locks from the tmp list to the head of
155 				 * the file's list.
156 				 */
157 				cifs_move_llist(&tmp_llist,
158 						&cfile->llist->locks);
159 				rc = stored_rc;
160 			} else
161 				/*
162 				 * The unlock range request succeed - free the
163 				 * tmp list.
164 				 */
165 				cifs_free_llist(&tmp_llist);
166 			cur = buf;
167 			num = 0;
168 		} else
169 			cur++;
170 	}
171 	if (num) {
172 		stored_rc = smb2_lockv(xid, tcon, cfile->fid.persistent_fid,
173 				       cfile->fid.volatile_fid, current->tgid,
174 				       num, buf);
175 		if (stored_rc) {
176 			cifs_move_llist(&tmp_llist, &cfile->llist->locks);
177 			rc = stored_rc;
178 		} else
179 			cifs_free_llist(&tmp_llist);
180 	}
181 	up_write(&cinode->lock_sem);
182 
183 	kfree(buf);
184 	return rc;
185 }
186 
187 static int
smb2_push_mand_fdlocks(struct cifs_fid_locks * fdlocks,const unsigned int xid,struct smb2_lock_element * buf,unsigned int max_num)188 smb2_push_mand_fdlocks(struct cifs_fid_locks *fdlocks, const unsigned int xid,
189 		       struct smb2_lock_element *buf, unsigned int max_num)
190 {
191 	int rc = 0, stored_rc;
192 	struct cifsFileInfo *cfile = fdlocks->cfile;
193 	struct cifsLockInfo *li;
194 	unsigned int num = 0;
195 	struct smb2_lock_element *cur = buf;
196 	struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
197 
198 	list_for_each_entry(li, &fdlocks->locks, llist) {
199 		cur->Length = cpu_to_le64(li->length);
200 		cur->Offset = cpu_to_le64(li->offset);
201 		cur->Flags = cpu_to_le32(li->type |
202 						SMB2_LOCKFLAG_FAIL_IMMEDIATELY);
203 		if (++num == max_num) {
204 			stored_rc = smb2_lockv(xid, tcon,
205 					       cfile->fid.persistent_fid,
206 					       cfile->fid.volatile_fid,
207 					       current->tgid, num, buf);
208 			if (stored_rc)
209 				rc = stored_rc;
210 			cur = buf;
211 			num = 0;
212 		} else
213 			cur++;
214 	}
215 	if (num) {
216 		stored_rc = smb2_lockv(xid, tcon,
217 				       cfile->fid.persistent_fid,
218 				       cfile->fid.volatile_fid,
219 				       current->tgid, num, buf);
220 		if (stored_rc)
221 			rc = stored_rc;
222 	}
223 
224 	return rc;
225 }
226 
227 int
smb2_push_mandatory_locks(struct cifsFileInfo * cfile)228 smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
229 {
230 	int rc = 0, stored_rc;
231 	unsigned int xid;
232 	unsigned int max_num, max_buf;
233 	struct smb2_lock_element *buf;
234 	struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
235 	struct cifs_fid_locks *fdlocks;
236 
237 	xid = get_xid();
238 
239 	/*
240 	 * Accessing maxBuf is racy with cifs_reconnect - need to store value
241 	 * and check it for zero before using.
242 	 */
243 	max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
244 	if (!max_buf) {
245 		free_xid(xid);
246 		return -EINVAL;
247 	}
248 
249 	max_num = max_buf / sizeof(struct smb2_lock_element);
250 	buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
251 	if (!buf) {
252 		free_xid(xid);
253 		return -ENOMEM;
254 	}
255 
256 	list_for_each_entry(fdlocks, &cinode->llist, llist) {
257 		stored_rc = smb2_push_mand_fdlocks(fdlocks, xid, buf, max_num);
258 		if (stored_rc)
259 			rc = stored_rc;
260 	}
261 
262 	kfree(buf);
263 	free_xid(xid);
264 	return rc;
265 }
266