smb2file.c (7488B)
1// SPDX-License-Identifier: LGPL-2.1 2/* 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 */ 9#include <linux/fs.h> 10#include <linux/stat.h> 11#include <linux/slab.h> 12#include <linux/pagemap.h> 13#include <asm/div64.h> 14#include "cifsfs.h" 15#include "cifspdu.h" 16#include "cifsglob.h" 17#include "cifsproto.h" 18#include "cifs_debug.h" 19#include "cifs_fs_sb.h" 20#include "cifs_unicode.h" 21#include "fscache.h" 22#include "smb2proto.h" 23 24int 25smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, 26 __u32 *oplock, FILE_ALL_INFO *buf) 27{ 28 int rc; 29 __le16 *smb2_path; 30 struct smb2_file_all_info *smb2_data = NULL; 31 __u8 smb2_oplock; 32 struct cifs_fid *fid = oparms->fid; 33 struct network_resiliency_req nr_ioctl_req; 34 35 smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb); 36 if (smb2_path == NULL) { 37 rc = -ENOMEM; 38 goto out; 39 } 40 41 smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2, 42 GFP_KERNEL); 43 if (smb2_data == NULL) { 44 rc = -ENOMEM; 45 goto out; 46 } 47 48 oparms->desired_access |= FILE_READ_ATTRIBUTES; 49 smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH; 50 51 rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, 52 NULL, NULL); 53 if (rc) 54 goto out; 55 56 57 if (oparms->tcon->use_resilient) { 58 /* default timeout is 0, servers pick default (120 seconds) */ 59 nr_ioctl_req.Timeout = 60 cpu_to_le32(oparms->tcon->handle_timeout); 61 nr_ioctl_req.Reserved = 0; 62 rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid, 63 fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY, 64 true /* is_fsctl */, 65 (char *)&nr_ioctl_req, sizeof(nr_ioctl_req), 66 CIFSMaxBufSize, NULL, NULL /* no return info */); 67 if (rc == -EOPNOTSUPP) { 68 cifs_dbg(VFS, 69 "resiliency not supported by server, disabling\n"); 70 oparms->tcon->use_resilient = false; 71 } else if (rc) 72 cifs_dbg(FYI, "error %d setting resiliency\n", rc); 73 74 rc = 0; 75 } 76 77 if (buf) { 78 /* if open response does not have IndexNumber field - get it */ 79 if (smb2_data->IndexNumber == 0) { 80 rc = SMB2_get_srv_num(xid, oparms->tcon, 81 fid->persistent_fid, 82 fid->volatile_fid, 83 &smb2_data->IndexNumber); 84 if (rc) { 85 /* 86 * let get_inode_info disable server inode 87 * numbers 88 */ 89 smb2_data->IndexNumber = 0; 90 rc = 0; 91 } 92 } 93 move_smb2_info_to_cifs(buf, smb2_data); 94 } 95 96 *oplock = smb2_oplock; 97out: 98 kfree(smb2_data); 99 kfree(smb2_path); 100 return rc; 101} 102 103int 104smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, 105 const unsigned int xid) 106{ 107 int rc = 0, stored_rc; 108 unsigned int max_num, num = 0, max_buf; 109 struct smb2_lock_element *buf, *cur; 110 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 111 struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); 112 struct cifsLockInfo *li, *tmp; 113 __u64 length = 1 + flock->fl_end - flock->fl_start; 114 struct list_head tmp_llist; 115 116 INIT_LIST_HEAD(&tmp_llist); 117 118 /* 119 * Accessing maxBuf is racy with cifs_reconnect - need to store value 120 * and check it before using. 121 */ 122 max_buf = tcon->ses->server->maxBuf; 123 if (max_buf < sizeof(struct smb2_lock_element)) 124 return -EINVAL; 125 126 BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE); 127 max_buf = min_t(unsigned int, max_buf, PAGE_SIZE); 128 max_num = max_buf / sizeof(struct smb2_lock_element); 129 buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL); 130 if (!buf) 131 return -ENOMEM; 132 133 cur = buf; 134 135 cifs_down_write(&cinode->lock_sem); 136 list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) { 137 if (flock->fl_start > li->offset || 138 (flock->fl_start + length) < 139 (li->offset + li->length)) 140 continue; 141 if (current->tgid != li->pid) 142 /* 143 * flock and OFD lock are associated with an open 144 * file description, not the process. 145 */ 146 if (!(flock->fl_flags & (FL_FLOCK | FL_OFDLCK))) 147 continue; 148 if (cinode->can_cache_brlcks) { 149 /* 150 * We can cache brlock requests - simply remove a lock 151 * from the file's list. 152 */ 153 list_del(&li->llist); 154 cifs_del_lock_waiters(li); 155 kfree(li); 156 continue; 157 } 158 cur->Length = cpu_to_le64(li->length); 159 cur->Offset = cpu_to_le64(li->offset); 160 cur->Flags = cpu_to_le32(SMB2_LOCKFLAG_UNLOCK); 161 /* 162 * We need to save a lock here to let us add it again to the 163 * file's list if the unlock range request fails on the server. 164 */ 165 list_move(&li->llist, &tmp_llist); 166 if (++num == max_num) { 167 stored_rc = smb2_lockv(xid, tcon, 168 cfile->fid.persistent_fid, 169 cfile->fid.volatile_fid, 170 current->tgid, num, buf); 171 if (stored_rc) { 172 /* 173 * We failed on the unlock range request - add 174 * all locks from the tmp list to the head of 175 * the file's list. 176 */ 177 cifs_move_llist(&tmp_llist, 178 &cfile->llist->locks); 179 rc = stored_rc; 180 } else 181 /* 182 * The unlock range request succeed - free the 183 * tmp list. 184 */ 185 cifs_free_llist(&tmp_llist); 186 cur = buf; 187 num = 0; 188 } else 189 cur++; 190 } 191 if (num) { 192 stored_rc = smb2_lockv(xid, tcon, cfile->fid.persistent_fid, 193 cfile->fid.volatile_fid, current->tgid, 194 num, buf); 195 if (stored_rc) { 196 cifs_move_llist(&tmp_llist, &cfile->llist->locks); 197 rc = stored_rc; 198 } else 199 cifs_free_llist(&tmp_llist); 200 } 201 up_write(&cinode->lock_sem); 202 203 kfree(buf); 204 return rc; 205} 206 207static int 208smb2_push_mand_fdlocks(struct cifs_fid_locks *fdlocks, const unsigned int xid, 209 struct smb2_lock_element *buf, unsigned int max_num) 210{ 211 int rc = 0, stored_rc; 212 struct cifsFileInfo *cfile = fdlocks->cfile; 213 struct cifsLockInfo *li; 214 unsigned int num = 0; 215 struct smb2_lock_element *cur = buf; 216 struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 217 218 list_for_each_entry(li, &fdlocks->locks, llist) { 219 cur->Length = cpu_to_le64(li->length); 220 cur->Offset = cpu_to_le64(li->offset); 221 cur->Flags = cpu_to_le32(li->type | 222 SMB2_LOCKFLAG_FAIL_IMMEDIATELY); 223 if (++num == max_num) { 224 stored_rc = smb2_lockv(xid, tcon, 225 cfile->fid.persistent_fid, 226 cfile->fid.volatile_fid, 227 current->tgid, num, buf); 228 if (stored_rc) 229 rc = stored_rc; 230 cur = buf; 231 num = 0; 232 } else 233 cur++; 234 } 235 if (num) { 236 stored_rc = smb2_lockv(xid, tcon, 237 cfile->fid.persistent_fid, 238 cfile->fid.volatile_fid, 239 current->tgid, num, buf); 240 if (stored_rc) 241 rc = stored_rc; 242 } 243 244 return rc; 245} 246 247int 248smb2_push_mandatory_locks(struct cifsFileInfo *cfile) 249{ 250 int rc = 0, stored_rc; 251 unsigned int xid; 252 unsigned int max_num, max_buf; 253 struct smb2_lock_element *buf; 254 struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); 255 struct cifs_fid_locks *fdlocks; 256 257 xid = get_xid(); 258 259 /* 260 * Accessing maxBuf is racy with cifs_reconnect - need to store value 261 * and check it for zero before using. 262 */ 263 max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf; 264 if (max_buf < sizeof(struct smb2_lock_element)) { 265 free_xid(xid); 266 return -EINVAL; 267 } 268 269 BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE); 270 max_buf = min_t(unsigned int, max_buf, PAGE_SIZE); 271 max_num = max_buf / sizeof(struct smb2_lock_element); 272 buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL); 273 if (!buf) { 274 free_xid(xid); 275 return -ENOMEM; 276 } 277 278 list_for_each_entry(fdlocks, &cinode->llist, llist) { 279 stored_rc = smb2_push_mand_fdlocks(fdlocks, xid, buf, max_num); 280 if (stored_rc) 281 rc = stored_rc; 282 } 283 284 kfree(buf); 285 free_xid(xid); 286 return rc; 287}