162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2002, 2011 562306a36Sopenharmony_ci * Author(s): Steve French (sfrench@us.ibm.com), 662306a36Sopenharmony_ci * Pavel Shilovsky ((pshilovsky@samba.org) 2012 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/fs.h> 1062306a36Sopenharmony_ci#include <linux/filelock.h> 1162306a36Sopenharmony_ci#include <linux/stat.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/pagemap.h> 1462306a36Sopenharmony_ci#include <asm/div64.h> 1562306a36Sopenharmony_ci#include "cifsfs.h" 1662306a36Sopenharmony_ci#include "cifspdu.h" 1762306a36Sopenharmony_ci#include "cifsglob.h" 1862306a36Sopenharmony_ci#include "cifsproto.h" 1962306a36Sopenharmony_ci#include "cifs_debug.h" 2062306a36Sopenharmony_ci#include "cifs_fs_sb.h" 2162306a36Sopenharmony_ci#include "cifs_unicode.h" 2262306a36Sopenharmony_ci#include "fscache.h" 2362306a36Sopenharmony_ci#include "smb2proto.h" 2462306a36Sopenharmony_ci#include "smb2status.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic struct smb2_symlink_err_rsp *symlink_data(const struct kvec *iov) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct smb2_err_rsp *err = iov->iov_base; 2962306a36Sopenharmony_ci struct smb2_symlink_err_rsp *sym = ERR_PTR(-EINVAL); 3062306a36Sopenharmony_ci u32 len; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (err->ErrorContextCount) { 3362306a36Sopenharmony_ci struct smb2_error_context_rsp *p, *end; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci len = (u32)err->ErrorContextCount * (offsetof(struct smb2_error_context_rsp, 3662306a36Sopenharmony_ci ErrorContextData) + 3762306a36Sopenharmony_ci sizeof(struct smb2_symlink_err_rsp)); 3862306a36Sopenharmony_ci if (le32_to_cpu(err->ByteCount) < len || iov->iov_len < len + sizeof(*err) + 1) 3962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci p = (struct smb2_error_context_rsp *)err->ErrorData; 4262306a36Sopenharmony_ci end = (struct smb2_error_context_rsp *)((u8 *)err + iov->iov_len); 4362306a36Sopenharmony_ci do { 4462306a36Sopenharmony_ci if (le32_to_cpu(p->ErrorId) == SMB2_ERROR_ID_DEFAULT) { 4562306a36Sopenharmony_ci sym = (struct smb2_symlink_err_rsp *)&p->ErrorContextData; 4662306a36Sopenharmony_ci break; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci cifs_dbg(FYI, "%s: skipping unhandled error context: 0x%x\n", 4962306a36Sopenharmony_ci __func__, le32_to_cpu(p->ErrorId)); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci len = ALIGN(le32_to_cpu(p->ErrorDataLength), 8); 5262306a36Sopenharmony_ci p = (struct smb2_error_context_rsp *)((u8 *)&p->ErrorContextData + len); 5362306a36Sopenharmony_ci } while (p < end); 5462306a36Sopenharmony_ci } else if (le32_to_cpu(err->ByteCount) >= sizeof(*sym) && 5562306a36Sopenharmony_ci iov->iov_len >= SMB2_SYMLINK_STRUCT_SIZE) { 5662306a36Sopenharmony_ci sym = (struct smb2_symlink_err_rsp *)err->ErrorData; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (!IS_ERR(sym) && (le32_to_cpu(sym->SymLinkErrorTag) != SYMLINK_ERROR_TAG || 6062306a36Sopenharmony_ci le32_to_cpu(sym->ReparseTag) != IO_REPARSE_TAG_SYMLINK)) 6162306a36Sopenharmony_ci sym = ERR_PTR(-EINVAL); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return sym; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciint smb2_parse_symlink_response(struct cifs_sb_info *cifs_sb, const struct kvec *iov, char **path) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct smb2_symlink_err_rsp *sym; 6962306a36Sopenharmony_ci unsigned int sub_offs, sub_len; 7062306a36Sopenharmony_ci unsigned int print_offs, print_len; 7162306a36Sopenharmony_ci char *s; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (!cifs_sb || !iov || !iov->iov_base || !iov->iov_len || !path) 7462306a36Sopenharmony_ci return -EINVAL; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci sym = symlink_data(iov); 7762306a36Sopenharmony_ci if (IS_ERR(sym)) 7862306a36Sopenharmony_ci return PTR_ERR(sym); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci sub_len = le16_to_cpu(sym->SubstituteNameLength); 8162306a36Sopenharmony_ci sub_offs = le16_to_cpu(sym->SubstituteNameOffset); 8262306a36Sopenharmony_ci print_len = le16_to_cpu(sym->PrintNameLength); 8362306a36Sopenharmony_ci print_offs = le16_to_cpu(sym->PrintNameOffset); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (iov->iov_len < SMB2_SYMLINK_STRUCT_SIZE + sub_offs + sub_len || 8662306a36Sopenharmony_ci iov->iov_len < SMB2_SYMLINK_STRUCT_SIZE + print_offs + print_len) 8762306a36Sopenharmony_ci return -EINVAL; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci s = cifs_strndup_from_utf16((char *)sym->PathBuffer + sub_offs, sub_len, true, 9062306a36Sopenharmony_ci cifs_sb->local_nls); 9162306a36Sopenharmony_ci if (!s) 9262306a36Sopenharmony_ci return -ENOMEM; 9362306a36Sopenharmony_ci convert_delimiter(s, '/'); 9462306a36Sopenharmony_ci cifs_dbg(FYI, "%s: symlink target: %s\n", __func__, s); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci *path = s; 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ciint smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock, void *buf) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci int rc; 10362306a36Sopenharmony_ci __le16 *smb2_path; 10462306a36Sopenharmony_ci __u8 smb2_oplock; 10562306a36Sopenharmony_ci struct cifs_open_info_data *data = buf; 10662306a36Sopenharmony_ci struct smb2_file_all_info file_info = {}; 10762306a36Sopenharmony_ci struct smb2_file_all_info *smb2_data = data ? &file_info : NULL; 10862306a36Sopenharmony_ci struct kvec err_iov = {}; 10962306a36Sopenharmony_ci int err_buftype = CIFS_NO_BUFFER; 11062306a36Sopenharmony_ci struct cifs_fid *fid = oparms->fid; 11162306a36Sopenharmony_ci struct network_resiliency_req nr_ioctl_req; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb); 11462306a36Sopenharmony_ci if (smb2_path == NULL) 11562306a36Sopenharmony_ci return -ENOMEM; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci oparms->desired_access |= FILE_READ_ATTRIBUTES; 11862306a36Sopenharmony_ci smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov, 12162306a36Sopenharmony_ci &err_buftype); 12262306a36Sopenharmony_ci if (rc && data) { 12362306a36Sopenharmony_ci struct smb2_hdr *hdr = err_iov.iov_base; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (unlikely(!err_iov.iov_base || err_buftype == CIFS_NO_BUFFER)) 12662306a36Sopenharmony_ci goto out; 12762306a36Sopenharmony_ci if (hdr->Status == STATUS_STOPPED_ON_SYMLINK) { 12862306a36Sopenharmony_ci rc = smb2_parse_symlink_response(oparms->cifs_sb, &err_iov, 12962306a36Sopenharmony_ci &data->symlink_target); 13062306a36Sopenharmony_ci if (!rc) { 13162306a36Sopenharmony_ci memset(smb2_data, 0, sizeof(*smb2_data)); 13262306a36Sopenharmony_ci oparms->create_options |= OPEN_REPARSE_POINT; 13362306a36Sopenharmony_ci rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, 13462306a36Sopenharmony_ci NULL, NULL, NULL); 13562306a36Sopenharmony_ci oparms->create_options &= ~OPEN_REPARSE_POINT; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (rc) 14162306a36Sopenharmony_ci goto out; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (oparms->tcon->use_resilient) { 14462306a36Sopenharmony_ci /* default timeout is 0, servers pick default (120 seconds) */ 14562306a36Sopenharmony_ci nr_ioctl_req.Timeout = 14662306a36Sopenharmony_ci cpu_to_le32(oparms->tcon->handle_timeout); 14762306a36Sopenharmony_ci nr_ioctl_req.Reserved = 0; 14862306a36Sopenharmony_ci rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid, 14962306a36Sopenharmony_ci fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY, 15062306a36Sopenharmony_ci (char *)&nr_ioctl_req, sizeof(nr_ioctl_req), 15162306a36Sopenharmony_ci CIFSMaxBufSize, NULL, NULL /* no return info */); 15262306a36Sopenharmony_ci if (rc == -EOPNOTSUPP) { 15362306a36Sopenharmony_ci cifs_dbg(VFS, 15462306a36Sopenharmony_ci "resiliency not supported by server, disabling\n"); 15562306a36Sopenharmony_ci oparms->tcon->use_resilient = false; 15662306a36Sopenharmony_ci } else if (rc) 15762306a36Sopenharmony_ci cifs_dbg(FYI, "error %d setting resiliency\n", rc); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci rc = 0; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (smb2_data) { 16362306a36Sopenharmony_ci /* if open response does not have IndexNumber field - get it */ 16462306a36Sopenharmony_ci if (smb2_data->IndexNumber == 0) { 16562306a36Sopenharmony_ci rc = SMB2_get_srv_num(xid, oparms->tcon, 16662306a36Sopenharmony_ci fid->persistent_fid, 16762306a36Sopenharmony_ci fid->volatile_fid, 16862306a36Sopenharmony_ci &smb2_data->IndexNumber); 16962306a36Sopenharmony_ci if (rc) { 17062306a36Sopenharmony_ci /* 17162306a36Sopenharmony_ci * let get_inode_info disable server inode 17262306a36Sopenharmony_ci * numbers 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci smb2_data->IndexNumber = 0; 17562306a36Sopenharmony_ci rc = 0; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci memcpy(&data->fi, smb2_data, sizeof(data->fi)); 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci *oplock = smb2_oplock; 18262306a36Sopenharmony_ciout: 18362306a36Sopenharmony_ci free_rsp_buf(err_buftype, err_iov.iov_base); 18462306a36Sopenharmony_ci kfree(smb2_path); 18562306a36Sopenharmony_ci return rc; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ciint 18962306a36Sopenharmony_cismb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, 19062306a36Sopenharmony_ci const unsigned int xid) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci int rc = 0, stored_rc; 19362306a36Sopenharmony_ci unsigned int max_num, num = 0, max_buf; 19462306a36Sopenharmony_ci struct smb2_lock_element *buf, *cur; 19562306a36Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 19662306a36Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); 19762306a36Sopenharmony_ci struct cifsLockInfo *li, *tmp; 19862306a36Sopenharmony_ci __u64 length = 1 + flock->fl_end - flock->fl_start; 19962306a36Sopenharmony_ci struct list_head tmp_llist; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci INIT_LIST_HEAD(&tmp_llist); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* 20462306a36Sopenharmony_ci * Accessing maxBuf is racy with cifs_reconnect - need to store value 20562306a36Sopenharmony_ci * and check it before using. 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_ci max_buf = tcon->ses->server->maxBuf; 20862306a36Sopenharmony_ci if (max_buf < sizeof(struct smb2_lock_element)) 20962306a36Sopenharmony_ci return -EINVAL; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE); 21262306a36Sopenharmony_ci max_buf = min_t(unsigned int, max_buf, PAGE_SIZE); 21362306a36Sopenharmony_ci max_num = max_buf / sizeof(struct smb2_lock_element); 21462306a36Sopenharmony_ci buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL); 21562306a36Sopenharmony_ci if (!buf) 21662306a36Sopenharmony_ci return -ENOMEM; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci cur = buf; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci cifs_down_write(&cinode->lock_sem); 22162306a36Sopenharmony_ci list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) { 22262306a36Sopenharmony_ci if (flock->fl_start > li->offset || 22362306a36Sopenharmony_ci (flock->fl_start + length) < 22462306a36Sopenharmony_ci (li->offset + li->length)) 22562306a36Sopenharmony_ci continue; 22662306a36Sopenharmony_ci if (current->tgid != li->pid) 22762306a36Sopenharmony_ci /* 22862306a36Sopenharmony_ci * flock and OFD lock are associated with an open 22962306a36Sopenharmony_ci * file description, not the process. 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_ci if (!(flock->fl_flags & (FL_FLOCK | FL_OFDLCK))) 23262306a36Sopenharmony_ci continue; 23362306a36Sopenharmony_ci if (cinode->can_cache_brlcks) { 23462306a36Sopenharmony_ci /* 23562306a36Sopenharmony_ci * We can cache brlock requests - simply remove a lock 23662306a36Sopenharmony_ci * from the file's list. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci list_del(&li->llist); 23962306a36Sopenharmony_ci cifs_del_lock_waiters(li); 24062306a36Sopenharmony_ci kfree(li); 24162306a36Sopenharmony_ci continue; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci cur->Length = cpu_to_le64(li->length); 24462306a36Sopenharmony_ci cur->Offset = cpu_to_le64(li->offset); 24562306a36Sopenharmony_ci cur->Flags = cpu_to_le32(SMB2_LOCKFLAG_UNLOCK); 24662306a36Sopenharmony_ci /* 24762306a36Sopenharmony_ci * We need to save a lock here to let us add it again to the 24862306a36Sopenharmony_ci * file's list if the unlock range request fails on the server. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci list_move(&li->llist, &tmp_llist); 25162306a36Sopenharmony_ci if (++num == max_num) { 25262306a36Sopenharmony_ci stored_rc = smb2_lockv(xid, tcon, 25362306a36Sopenharmony_ci cfile->fid.persistent_fid, 25462306a36Sopenharmony_ci cfile->fid.volatile_fid, 25562306a36Sopenharmony_ci current->tgid, num, buf); 25662306a36Sopenharmony_ci if (stored_rc) { 25762306a36Sopenharmony_ci /* 25862306a36Sopenharmony_ci * We failed on the unlock range request - add 25962306a36Sopenharmony_ci * all locks from the tmp list to the head of 26062306a36Sopenharmony_ci * the file's list. 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_ci cifs_move_llist(&tmp_llist, 26362306a36Sopenharmony_ci &cfile->llist->locks); 26462306a36Sopenharmony_ci rc = stored_rc; 26562306a36Sopenharmony_ci } else 26662306a36Sopenharmony_ci /* 26762306a36Sopenharmony_ci * The unlock range request succeed - free the 26862306a36Sopenharmony_ci * tmp list. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci cifs_free_llist(&tmp_llist); 27162306a36Sopenharmony_ci cur = buf; 27262306a36Sopenharmony_ci num = 0; 27362306a36Sopenharmony_ci } else 27462306a36Sopenharmony_ci cur++; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci if (num) { 27762306a36Sopenharmony_ci stored_rc = smb2_lockv(xid, tcon, cfile->fid.persistent_fid, 27862306a36Sopenharmony_ci cfile->fid.volatile_fid, current->tgid, 27962306a36Sopenharmony_ci num, buf); 28062306a36Sopenharmony_ci if (stored_rc) { 28162306a36Sopenharmony_ci cifs_move_llist(&tmp_llist, &cfile->llist->locks); 28262306a36Sopenharmony_ci rc = stored_rc; 28362306a36Sopenharmony_ci } else 28462306a36Sopenharmony_ci cifs_free_llist(&tmp_llist); 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci up_write(&cinode->lock_sem); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci kfree(buf); 28962306a36Sopenharmony_ci return rc; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic int 29362306a36Sopenharmony_cismb2_push_mand_fdlocks(struct cifs_fid_locks *fdlocks, const unsigned int xid, 29462306a36Sopenharmony_ci struct smb2_lock_element *buf, unsigned int max_num) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci int rc = 0, stored_rc; 29762306a36Sopenharmony_ci struct cifsFileInfo *cfile = fdlocks->cfile; 29862306a36Sopenharmony_ci struct cifsLockInfo *li; 29962306a36Sopenharmony_ci unsigned int num = 0; 30062306a36Sopenharmony_ci struct smb2_lock_element *cur = buf; 30162306a36Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci list_for_each_entry(li, &fdlocks->locks, llist) { 30462306a36Sopenharmony_ci cur->Length = cpu_to_le64(li->length); 30562306a36Sopenharmony_ci cur->Offset = cpu_to_le64(li->offset); 30662306a36Sopenharmony_ci cur->Flags = cpu_to_le32(li->type | 30762306a36Sopenharmony_ci SMB2_LOCKFLAG_FAIL_IMMEDIATELY); 30862306a36Sopenharmony_ci if (++num == max_num) { 30962306a36Sopenharmony_ci stored_rc = smb2_lockv(xid, tcon, 31062306a36Sopenharmony_ci cfile->fid.persistent_fid, 31162306a36Sopenharmony_ci cfile->fid.volatile_fid, 31262306a36Sopenharmony_ci current->tgid, num, buf); 31362306a36Sopenharmony_ci if (stored_rc) 31462306a36Sopenharmony_ci rc = stored_rc; 31562306a36Sopenharmony_ci cur = buf; 31662306a36Sopenharmony_ci num = 0; 31762306a36Sopenharmony_ci } else 31862306a36Sopenharmony_ci cur++; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci if (num) { 32162306a36Sopenharmony_ci stored_rc = smb2_lockv(xid, tcon, 32262306a36Sopenharmony_ci cfile->fid.persistent_fid, 32362306a36Sopenharmony_ci cfile->fid.volatile_fid, 32462306a36Sopenharmony_ci current->tgid, num, buf); 32562306a36Sopenharmony_ci if (stored_rc) 32662306a36Sopenharmony_ci rc = stored_rc; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return rc; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ciint 33362306a36Sopenharmony_cismb2_push_mandatory_locks(struct cifsFileInfo *cfile) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci int rc = 0, stored_rc; 33662306a36Sopenharmony_ci unsigned int xid; 33762306a36Sopenharmony_ci unsigned int max_num, max_buf; 33862306a36Sopenharmony_ci struct smb2_lock_element *buf; 33962306a36Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); 34062306a36Sopenharmony_ci struct cifs_fid_locks *fdlocks; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci xid = get_xid(); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* 34562306a36Sopenharmony_ci * Accessing maxBuf is racy with cifs_reconnect - need to store value 34662306a36Sopenharmony_ci * and check it for zero before using. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf; 34962306a36Sopenharmony_ci if (max_buf < sizeof(struct smb2_lock_element)) { 35062306a36Sopenharmony_ci free_xid(xid); 35162306a36Sopenharmony_ci return -EINVAL; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct smb2_lock_element) > PAGE_SIZE); 35562306a36Sopenharmony_ci max_buf = min_t(unsigned int, max_buf, PAGE_SIZE); 35662306a36Sopenharmony_ci max_num = max_buf / sizeof(struct smb2_lock_element); 35762306a36Sopenharmony_ci buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL); 35862306a36Sopenharmony_ci if (!buf) { 35962306a36Sopenharmony_ci free_xid(xid); 36062306a36Sopenharmony_ci return -ENOMEM; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci list_for_each_entry(fdlocks, &cinode->llist, llist) { 36462306a36Sopenharmony_ci stored_rc = smb2_push_mand_fdlocks(fdlocks, xid, buf, max_num); 36562306a36Sopenharmony_ci if (stored_rc) 36662306a36Sopenharmony_ci rc = stored_rc; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci kfree(buf); 37062306a36Sopenharmony_ci free_xid(xid); 37162306a36Sopenharmony_ci return rc; 37262306a36Sopenharmony_ci} 373