Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
smb2file.c
Go to the documentation of this file.
1 /*
2  * fs/cifs/smb2file.c
3  *
4  * Copyright (C) International Business Machines Corp., 2002, 2011
5  * Author(s): Steve French ([email protected]),
6  * Pavel Shilovsky (([email protected]) 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 void
38 smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
39 {
40  oplock &= 0xFF;
41  if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
42  return;
43  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 
59 int
60 smb2_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;
68  __u8 smb2_oplock[17];
69 
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;
84  *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);
88 
89  rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
90  &fid->volatile_fid, desired_access, disposition,
91  0, 0, smb2_oplock, smb2_data);
92  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 
108  *oplock = *smb2_oplock;
109 out:
110  kfree(smb2_data);
111  kfree(smb2_path);
112  return rc;
113 }
114 
115 int
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 
145  down_write(&cinode->lock_sem);
146  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);
160  kfree(li);
161  continue;
162  }
163  cur->Length = cpu_to_le64(li->length);
164  cur->Offset = cpu_to_le64(li->offset);
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  }
206  up_write(&cinode->lock_sem);
207 
208  kfree(buf);
209  return rc;
210 }
211 
212 static int
213 smb2_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 |
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 
252 int
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();
263  /* we are going to update can_cache_brlcks here - need a write access */
264  down_write(&cinode->lock_sem);
265  if (!cinode->can_cache_brlcks) {
266  up_write(&cinode->lock_sem);
267  free_xid(xid);
268  return rc;
269  }
270 
271  /*
272  * Accessing maxBuf is racy with cifs_reconnect - need to store value
273  * and check it for zero before using.
274  */
275  max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
276  if (!max_buf) {
277  up_write(&cinode->lock_sem);
278  free_xid(xid);
279  return -EINVAL;
280  }
281 
282  max_num = max_buf / sizeof(struct smb2_lock_element);
283  buf = kzalloc(max_num * sizeof(struct smb2_lock_element), GFP_KERNEL);
284  if (!buf) {
285  up_write(&cinode->lock_sem);
286  free_xid(xid);
287  return -ENOMEM;
288  }
289 
290  list_for_each_entry(fdlocks, &cinode->llist, llist) {
291  stored_rc = smb2_push_mand_fdlocks(fdlocks, xid, buf, max_num);
292  if (stored_rc)
293  rc = stored_rc;
294  }
295 
296  cinode->can_cache_brlcks = false;
297  kfree(buf);
298 
299  up_write(&cinode->lock_sem);
300  free_xid(xid);
301  return rc;
302 }