Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.7 302 lines 8.2 kB view raw
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 37void 38smb2_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 59int 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; 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; 109out: 110 kfree(smb2_data); 111 kfree(smb2_path); 112 return rc; 113} 114 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 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 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(); 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}