OSDN Git Service

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[uclinux-h8/linux.git] / fs / cifs / smb2file.c
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 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
116 smb2_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
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);
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         }
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 |
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
252 int
253 smb2_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();
263
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) {
270                 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) {
277                 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
287         kfree(buf);
288         free_xid(xid);
289         return rc;
290 }