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 37int 38smb2_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; 84out: 85 kfree(smb2_data); 86 kfree(smb2_path); 87 return rc; 88} 89 90int 91smb2_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 187static int 188smb2_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 227int 228smb2_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