18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * fs/cifs/file.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * vfs operations that deal with files 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2002,2010 78c2ecf20Sopenharmony_ci * Author(s): Steve French (sfrench@us.ibm.com) 88c2ecf20Sopenharmony_ci * Jeremy Allison (jra@samba.org) 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 118c2ecf20Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as published 128c2ecf20Sopenharmony_ci * by the Free Software Foundation; either version 2.1 of the License, or 138c2ecf20Sopenharmony_ci * (at your option) any later version. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * This library is distributed in the hope that it will be useful, 168c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 178c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 188c2ecf20Sopenharmony_ci * the GNU Lesser General Public License for more details. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public License 218c2ecf20Sopenharmony_ci * along with this library; if not, write to the Free Software 228c2ecf20Sopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci#include <linux/fs.h> 258c2ecf20Sopenharmony_ci#include <linux/backing-dev.h> 268c2ecf20Sopenharmony_ci#include <linux/stat.h> 278c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 288c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 298c2ecf20Sopenharmony_ci#include <linux/pagevec.h> 308c2ecf20Sopenharmony_ci#include <linux/writeback.h> 318c2ecf20Sopenharmony_ci#include <linux/task_io_accounting_ops.h> 328c2ecf20Sopenharmony_ci#include <linux/delay.h> 338c2ecf20Sopenharmony_ci#include <linux/mount.h> 348c2ecf20Sopenharmony_ci#include <linux/slab.h> 358c2ecf20Sopenharmony_ci#include <linux/swap.h> 368c2ecf20Sopenharmony_ci#include <linux/mm.h> 378c2ecf20Sopenharmony_ci#include <asm/div64.h> 388c2ecf20Sopenharmony_ci#include "cifsfs.h" 398c2ecf20Sopenharmony_ci#include "cifspdu.h" 408c2ecf20Sopenharmony_ci#include "cifsglob.h" 418c2ecf20Sopenharmony_ci#include "cifsproto.h" 428c2ecf20Sopenharmony_ci#include "cifs_unicode.h" 438c2ecf20Sopenharmony_ci#include "cifs_debug.h" 448c2ecf20Sopenharmony_ci#include "cifs_fs_sb.h" 458c2ecf20Sopenharmony_ci#include "fscache.h" 468c2ecf20Sopenharmony_ci#include "smbdirect.h" 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline int cifs_convert_flags(unsigned int flags) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci if ((flags & O_ACCMODE) == O_RDONLY) 518c2ecf20Sopenharmony_ci return GENERIC_READ; 528c2ecf20Sopenharmony_ci else if ((flags & O_ACCMODE) == O_WRONLY) 538c2ecf20Sopenharmony_ci return GENERIC_WRITE; 548c2ecf20Sopenharmony_ci else if ((flags & O_ACCMODE) == O_RDWR) { 558c2ecf20Sopenharmony_ci /* GENERIC_ALL is too much permission to request 568c2ecf20Sopenharmony_ci can cause unnecessary access denied on create */ 578c2ecf20Sopenharmony_ci /* return GENERIC_ALL; */ 588c2ecf20Sopenharmony_ci return (GENERIC_READ | GENERIC_WRITE); 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return (READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | 628c2ecf20Sopenharmony_ci FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA | 638c2ecf20Sopenharmony_ci FILE_READ_DATA); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic u32 cifs_posix_convert_flags(unsigned int flags) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci u32 posix_flags = 0; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if ((flags & O_ACCMODE) == O_RDONLY) 718c2ecf20Sopenharmony_ci posix_flags = SMB_O_RDONLY; 728c2ecf20Sopenharmony_ci else if ((flags & O_ACCMODE) == O_WRONLY) 738c2ecf20Sopenharmony_ci posix_flags = SMB_O_WRONLY; 748c2ecf20Sopenharmony_ci else if ((flags & O_ACCMODE) == O_RDWR) 758c2ecf20Sopenharmony_ci posix_flags = SMB_O_RDWR; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (flags & O_CREAT) { 788c2ecf20Sopenharmony_ci posix_flags |= SMB_O_CREAT; 798c2ecf20Sopenharmony_ci if (flags & O_EXCL) 808c2ecf20Sopenharmony_ci posix_flags |= SMB_O_EXCL; 818c2ecf20Sopenharmony_ci } else if (flags & O_EXCL) 828c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Application %s pid %d has incorrectly set O_EXCL flag but not O_CREAT on file open. Ignoring O_EXCL\n", 838c2ecf20Sopenharmony_ci current->comm, current->tgid); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (flags & O_TRUNC) 868c2ecf20Sopenharmony_ci posix_flags |= SMB_O_TRUNC; 878c2ecf20Sopenharmony_ci /* be safe and imply O_SYNC for O_DSYNC */ 888c2ecf20Sopenharmony_ci if (flags & O_DSYNC) 898c2ecf20Sopenharmony_ci posix_flags |= SMB_O_SYNC; 908c2ecf20Sopenharmony_ci if (flags & O_DIRECTORY) 918c2ecf20Sopenharmony_ci posix_flags |= SMB_O_DIRECTORY; 928c2ecf20Sopenharmony_ci if (flags & O_NOFOLLOW) 938c2ecf20Sopenharmony_ci posix_flags |= SMB_O_NOFOLLOW; 948c2ecf20Sopenharmony_ci if (flags & O_DIRECT) 958c2ecf20Sopenharmony_ci posix_flags |= SMB_O_DIRECT; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return posix_flags; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic inline int cifs_get_disposition(unsigned int flags) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) 1038c2ecf20Sopenharmony_ci return FILE_CREATE; 1048c2ecf20Sopenharmony_ci else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) 1058c2ecf20Sopenharmony_ci return FILE_OVERWRITE_IF; 1068c2ecf20Sopenharmony_ci else if ((flags & O_CREAT) == O_CREAT) 1078c2ecf20Sopenharmony_ci return FILE_OPEN_IF; 1088c2ecf20Sopenharmony_ci else if ((flags & O_TRUNC) == O_TRUNC) 1098c2ecf20Sopenharmony_ci return FILE_OVERWRITE; 1108c2ecf20Sopenharmony_ci else 1118c2ecf20Sopenharmony_ci return FILE_OPEN; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ciint cifs_posix_open(char *full_path, struct inode **pinode, 1158c2ecf20Sopenharmony_ci struct super_block *sb, int mode, unsigned int f_flags, 1168c2ecf20Sopenharmony_ci __u32 *poplock, __u16 *pnetfid, unsigned int xid) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int rc; 1198c2ecf20Sopenharmony_ci FILE_UNIX_BASIC_INFO *presp_data; 1208c2ecf20Sopenharmony_ci __u32 posix_flags = 0; 1218c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 1228c2ecf20Sopenharmony_ci struct cifs_fattr fattr; 1238c2ecf20Sopenharmony_ci struct tcon_link *tlink; 1248c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci cifs_dbg(FYI, "posix open %s\n", full_path); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); 1298c2ecf20Sopenharmony_ci if (presp_data == NULL) 1308c2ecf20Sopenharmony_ci return -ENOMEM; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci tlink = cifs_sb_tlink(cifs_sb); 1338c2ecf20Sopenharmony_ci if (IS_ERR(tlink)) { 1348c2ecf20Sopenharmony_ci rc = PTR_ERR(tlink); 1358c2ecf20Sopenharmony_ci goto posix_open_ret; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci tcon = tlink_tcon(tlink); 1398c2ecf20Sopenharmony_ci mode &= ~current_umask(); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci posix_flags = cifs_posix_convert_flags(f_flags); 1428c2ecf20Sopenharmony_ci rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, 1438c2ecf20Sopenharmony_ci poplock, full_path, cifs_sb->local_nls, 1448c2ecf20Sopenharmony_ci cifs_remap(cifs_sb)); 1458c2ecf20Sopenharmony_ci cifs_put_tlink(tlink); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (rc) 1488c2ecf20Sopenharmony_ci goto posix_open_ret; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (presp_data->Type == cpu_to_le32(-1)) 1518c2ecf20Sopenharmony_ci goto posix_open_ret; /* open ok, caller does qpathinfo */ 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (!pinode) 1548c2ecf20Sopenharmony_ci goto posix_open_ret; /* caller does not need info */ 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* get new inode and set it up */ 1598c2ecf20Sopenharmony_ci if (*pinode == NULL) { 1608c2ecf20Sopenharmony_ci cifs_fill_uniqueid(sb, &fattr); 1618c2ecf20Sopenharmony_ci *pinode = cifs_iget(sb, &fattr); 1628c2ecf20Sopenharmony_ci if (!*pinode) { 1638c2ecf20Sopenharmony_ci rc = -ENOMEM; 1648c2ecf20Sopenharmony_ci goto posix_open_ret; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci } else { 1678c2ecf20Sopenharmony_ci cifs_revalidate_mapping(*pinode); 1688c2ecf20Sopenharmony_ci cifs_fattr_to_inode(*pinode, &fattr); 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciposix_open_ret: 1728c2ecf20Sopenharmony_ci kfree(presp_data); 1738c2ecf20Sopenharmony_ci return rc; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int 1778c2ecf20Sopenharmony_cicifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, 1788c2ecf20Sopenharmony_ci struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock, 1798c2ecf20Sopenharmony_ci struct cifs_fid *fid, unsigned int xid) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci int rc; 1828c2ecf20Sopenharmony_ci int desired_access; 1838c2ecf20Sopenharmony_ci int disposition; 1848c2ecf20Sopenharmony_ci int create_options = CREATE_NOT_DIR; 1858c2ecf20Sopenharmony_ci FILE_ALL_INFO *buf; 1868c2ecf20Sopenharmony_ci struct TCP_Server_Info *server = tcon->ses->server; 1878c2ecf20Sopenharmony_ci struct cifs_open_parms oparms; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!server->ops->open) 1908c2ecf20Sopenharmony_ci return -ENOSYS; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci desired_access = cifs_convert_flags(f_flags); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/********************************************************************* 1958c2ecf20Sopenharmony_ci * open flag mapping table: 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * POSIX Flag CIFS Disposition 1988c2ecf20Sopenharmony_ci * ---------- ---------------- 1998c2ecf20Sopenharmony_ci * O_CREAT FILE_OPEN_IF 2008c2ecf20Sopenharmony_ci * O_CREAT | O_EXCL FILE_CREATE 2018c2ecf20Sopenharmony_ci * O_CREAT | O_TRUNC FILE_OVERWRITE_IF 2028c2ecf20Sopenharmony_ci * O_TRUNC FILE_OVERWRITE 2038c2ecf20Sopenharmony_ci * none of the above FILE_OPEN 2048c2ecf20Sopenharmony_ci * 2058c2ecf20Sopenharmony_ci * Note that there is not a direct match between disposition 2068c2ecf20Sopenharmony_ci * FILE_SUPERSEDE (ie create whether or not file exists although 2078c2ecf20Sopenharmony_ci * O_CREAT | O_TRUNC is similar but truncates the existing 2088c2ecf20Sopenharmony_ci * file rather than creating a new file as FILE_SUPERSEDE does 2098c2ecf20Sopenharmony_ci * (which uses the attributes / metadata passed in on open call) 2108c2ecf20Sopenharmony_ci *? 2118c2ecf20Sopenharmony_ci *? O_SYNC is a reasonable match to CIFS writethrough flag 2128c2ecf20Sopenharmony_ci *? and the read write flags match reasonably. O_LARGEFILE 2138c2ecf20Sopenharmony_ci *? is irrelevant because largefile support is always used 2148c2ecf20Sopenharmony_ci *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, 2158c2ecf20Sopenharmony_ci * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation 2168c2ecf20Sopenharmony_ci *********************************************************************/ 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci disposition = cifs_get_disposition(f_flags); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* BB pass O_SYNC flag through on file attributes .. BB */ 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); 2238c2ecf20Sopenharmony_ci if (!buf) 2248c2ecf20Sopenharmony_ci return -ENOMEM; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* O_SYNC also has bit for O_DSYNC so following check picks up either */ 2278c2ecf20Sopenharmony_ci if (f_flags & O_SYNC) 2288c2ecf20Sopenharmony_ci create_options |= CREATE_WRITE_THROUGH; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (f_flags & O_DIRECT) 2318c2ecf20Sopenharmony_ci create_options |= CREATE_NO_BUFFER; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci oparms.tcon = tcon; 2348c2ecf20Sopenharmony_ci oparms.cifs_sb = cifs_sb; 2358c2ecf20Sopenharmony_ci oparms.desired_access = desired_access; 2368c2ecf20Sopenharmony_ci oparms.create_options = cifs_create_options(cifs_sb, create_options); 2378c2ecf20Sopenharmony_ci oparms.disposition = disposition; 2388c2ecf20Sopenharmony_ci oparms.path = full_path; 2398c2ecf20Sopenharmony_ci oparms.fid = fid; 2408c2ecf20Sopenharmony_ci oparms.reconnect = false; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci rc = server->ops->open(xid, &oparms, oplock, buf); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (rc) 2458c2ecf20Sopenharmony_ci goto out; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* TODO: Add support for calling posix query info but with passing in fid */ 2488c2ecf20Sopenharmony_ci if (tcon->unix_ext) 2498c2ecf20Sopenharmony_ci rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, 2508c2ecf20Sopenharmony_ci xid); 2518c2ecf20Sopenharmony_ci else 2528c2ecf20Sopenharmony_ci rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, 2538c2ecf20Sopenharmony_ci xid, fid); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (rc) { 2568c2ecf20Sopenharmony_ci server->ops->close(xid, tcon, fid); 2578c2ecf20Sopenharmony_ci if (rc == -ESTALE) 2588c2ecf20Sopenharmony_ci rc = -EOPENSTALE; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ciout: 2628c2ecf20Sopenharmony_ci kfree(buf); 2638c2ecf20Sopenharmony_ci return rc; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic bool 2678c2ecf20Sopenharmony_cicifs_has_mand_locks(struct cifsInodeInfo *cinode) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct cifs_fid_locks *cur; 2708c2ecf20Sopenharmony_ci bool has_locks = false; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci down_read(&cinode->lock_sem); 2738c2ecf20Sopenharmony_ci list_for_each_entry(cur, &cinode->llist, llist) { 2748c2ecf20Sopenharmony_ci if (!list_empty(&cur->locks)) { 2758c2ecf20Sopenharmony_ci has_locks = true; 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci up_read(&cinode->lock_sem); 2808c2ecf20Sopenharmony_ci return has_locks; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_civoid 2848c2ecf20Sopenharmony_cicifs_down_write(struct rw_semaphore *sem) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci while (!down_write_trylock(sem)) 2878c2ecf20Sopenharmony_ci msleep(10); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void cifsFileInfo_put_work(struct work_struct *work); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistruct cifsFileInfo * 2938c2ecf20Sopenharmony_cicifs_new_fileinfo(struct cifs_fid *fid, struct file *file, 2948c2ecf20Sopenharmony_ci struct tcon_link *tlink, __u32 oplock) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct dentry *dentry = file_dentry(file); 2978c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 2988c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(inode); 2998c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile; 3008c2ecf20Sopenharmony_ci struct cifs_fid_locks *fdlocks; 3018c2ecf20Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(tlink); 3028c2ecf20Sopenharmony_ci struct TCP_Server_Info *server = tcon->ses->server; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); 3058c2ecf20Sopenharmony_ci if (cfile == NULL) 3068c2ecf20Sopenharmony_ci return cfile; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci fdlocks = kzalloc(sizeof(struct cifs_fid_locks), GFP_KERNEL); 3098c2ecf20Sopenharmony_ci if (!fdlocks) { 3108c2ecf20Sopenharmony_ci kfree(cfile); 3118c2ecf20Sopenharmony_ci return NULL; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&fdlocks->locks); 3158c2ecf20Sopenharmony_ci fdlocks->cfile = cfile; 3168c2ecf20Sopenharmony_ci cfile->llist = fdlocks; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci cfile->count = 1; 3198c2ecf20Sopenharmony_ci cfile->pid = current->tgid; 3208c2ecf20Sopenharmony_ci cfile->uid = current_fsuid(); 3218c2ecf20Sopenharmony_ci cfile->dentry = dget(dentry); 3228c2ecf20Sopenharmony_ci cfile->f_flags = file->f_flags; 3238c2ecf20Sopenharmony_ci cfile->invalidHandle = false; 3248c2ecf20Sopenharmony_ci cfile->tlink = cifs_get_tlink(tlink); 3258c2ecf20Sopenharmony_ci INIT_WORK(&cfile->oplock_break, cifs_oplock_break); 3268c2ecf20Sopenharmony_ci INIT_WORK(&cfile->put, cifsFileInfo_put_work); 3278c2ecf20Sopenharmony_ci mutex_init(&cfile->fh_mutex); 3288c2ecf20Sopenharmony_ci spin_lock_init(&cfile->file_info_lock); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci cifs_sb_active(inode->i_sb); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* 3338c2ecf20Sopenharmony_ci * If the server returned a read oplock and we have mandatory brlocks, 3348c2ecf20Sopenharmony_ci * set oplock level to None. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci if (server->ops->is_read_op(oplock) && cifs_has_mand_locks(cinode)) { 3378c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Reset oplock val from read to None due to mand locks\n"); 3388c2ecf20Sopenharmony_ci oplock = 0; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci cifs_down_write(&cinode->lock_sem); 3428c2ecf20Sopenharmony_ci list_add(&fdlocks->llist, &cinode->llist); 3438c2ecf20Sopenharmony_ci up_write(&cinode->lock_sem); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci spin_lock(&tcon->open_file_lock); 3468c2ecf20Sopenharmony_ci if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE && oplock) 3478c2ecf20Sopenharmony_ci oplock = fid->pending_open->oplock; 3488c2ecf20Sopenharmony_ci list_del(&fid->pending_open->olist); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci fid->purge_cache = false; 3518c2ecf20Sopenharmony_ci server->ops->set_fid(cfile, fid, oplock); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci list_add(&cfile->tlist, &tcon->openFileList); 3548c2ecf20Sopenharmony_ci atomic_inc(&tcon->num_local_opens); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* if readable file instance put first in list*/ 3578c2ecf20Sopenharmony_ci spin_lock(&cinode->open_file_lock); 3588c2ecf20Sopenharmony_ci if (file->f_mode & FMODE_READ) 3598c2ecf20Sopenharmony_ci list_add(&cfile->flist, &cinode->openFileList); 3608c2ecf20Sopenharmony_ci else 3618c2ecf20Sopenharmony_ci list_add_tail(&cfile->flist, &cinode->openFileList); 3628c2ecf20Sopenharmony_ci spin_unlock(&cinode->open_file_lock); 3638c2ecf20Sopenharmony_ci spin_unlock(&tcon->open_file_lock); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (fid->purge_cache) 3668c2ecf20Sopenharmony_ci cifs_zap_mapping(inode); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci file->private_data = cfile; 3698c2ecf20Sopenharmony_ci return cfile; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistruct cifsFileInfo * 3738c2ecf20Sopenharmony_cicifsFileInfo_get(struct cifsFileInfo *cifs_file) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci spin_lock(&cifs_file->file_info_lock); 3768c2ecf20Sopenharmony_ci cifsFileInfo_get_locked(cifs_file); 3778c2ecf20Sopenharmony_ci spin_unlock(&cifs_file->file_info_lock); 3788c2ecf20Sopenharmony_ci return cifs_file; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct inode *inode = d_inode(cifs_file->dentry); 3848c2ecf20Sopenharmony_ci struct cifsInodeInfo *cifsi = CIFS_I(inode); 3858c2ecf20Sopenharmony_ci struct cifsLockInfo *li, *tmp; 3868c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* 3898c2ecf20Sopenharmony_ci * Delete any outstanding lock records. We'll lose them when the file 3908c2ecf20Sopenharmony_ci * is closed anyway. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci cifs_down_write(&cifsi->lock_sem); 3938c2ecf20Sopenharmony_ci list_for_each_entry_safe(li, tmp, &cifs_file->llist->locks, llist) { 3948c2ecf20Sopenharmony_ci list_del(&li->llist); 3958c2ecf20Sopenharmony_ci cifs_del_lock_waiters(li); 3968c2ecf20Sopenharmony_ci kfree(li); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci list_del(&cifs_file->llist->llist); 3998c2ecf20Sopenharmony_ci kfree(cifs_file->llist); 4008c2ecf20Sopenharmony_ci up_write(&cifsi->lock_sem); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci cifs_put_tlink(cifs_file->tlink); 4038c2ecf20Sopenharmony_ci dput(cifs_file->dentry); 4048c2ecf20Sopenharmony_ci cifs_sb_deactive(sb); 4058c2ecf20Sopenharmony_ci kfree(cifs_file); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic void cifsFileInfo_put_work(struct work_struct *work) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct cifsFileInfo *cifs_file = container_of(work, 4118c2ecf20Sopenharmony_ci struct cifsFileInfo, put); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci cifsFileInfo_put_final(cifs_file); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/** 4178c2ecf20Sopenharmony_ci * cifsFileInfo_put - release a reference of file priv data 4188c2ecf20Sopenharmony_ci * 4198c2ecf20Sopenharmony_ci * Always potentially wait for oplock handler. See _cifsFileInfo_put(). 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_civoid cifsFileInfo_put(struct cifsFileInfo *cifs_file) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci _cifsFileInfo_put(cifs_file, true, true); 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/** 4278c2ecf20Sopenharmony_ci * _cifsFileInfo_put - release a reference of file priv data 4288c2ecf20Sopenharmony_ci * 4298c2ecf20Sopenharmony_ci * This may involve closing the filehandle @cifs_file out on the 4308c2ecf20Sopenharmony_ci * server. Must be called without holding tcon->open_file_lock, 4318c2ecf20Sopenharmony_ci * cinode->open_file_lock and cifs_file->file_info_lock. 4328c2ecf20Sopenharmony_ci * 4338c2ecf20Sopenharmony_ci * If @wait_for_oplock_handler is true and we are releasing the last 4348c2ecf20Sopenharmony_ci * reference, wait for any running oplock break handler of the file 4358c2ecf20Sopenharmony_ci * and cancel any pending one. If calling this function from the 4368c2ecf20Sopenharmony_ci * oplock break handler, you need to pass false. 4378c2ecf20Sopenharmony_ci * 4388c2ecf20Sopenharmony_ci */ 4398c2ecf20Sopenharmony_civoid _cifsFileInfo_put(struct cifsFileInfo *cifs_file, 4408c2ecf20Sopenharmony_ci bool wait_oplock_handler, bool offload) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct inode *inode = d_inode(cifs_file->dentry); 4438c2ecf20Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink); 4448c2ecf20Sopenharmony_ci struct TCP_Server_Info *server = tcon->ses->server; 4458c2ecf20Sopenharmony_ci struct cifsInodeInfo *cifsi = CIFS_I(inode); 4468c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 4478c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 4488c2ecf20Sopenharmony_ci struct cifs_fid fid; 4498c2ecf20Sopenharmony_ci struct cifs_pending_open open; 4508c2ecf20Sopenharmony_ci bool oplock_break_cancelled; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci spin_lock(&tcon->open_file_lock); 4538c2ecf20Sopenharmony_ci spin_lock(&cifsi->open_file_lock); 4548c2ecf20Sopenharmony_ci spin_lock(&cifs_file->file_info_lock); 4558c2ecf20Sopenharmony_ci if (--cifs_file->count > 0) { 4568c2ecf20Sopenharmony_ci spin_unlock(&cifs_file->file_info_lock); 4578c2ecf20Sopenharmony_ci spin_unlock(&cifsi->open_file_lock); 4588c2ecf20Sopenharmony_ci spin_unlock(&tcon->open_file_lock); 4598c2ecf20Sopenharmony_ci return; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci spin_unlock(&cifs_file->file_info_lock); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (server->ops->get_lease_key) 4648c2ecf20Sopenharmony_ci server->ops->get_lease_key(inode, &fid); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* store open in pending opens to make sure we don't miss lease break */ 4678c2ecf20Sopenharmony_ci cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* remove it from the lists */ 4708c2ecf20Sopenharmony_ci list_del(&cifs_file->flist); 4718c2ecf20Sopenharmony_ci list_del(&cifs_file->tlist); 4728c2ecf20Sopenharmony_ci atomic_dec(&tcon->num_local_opens); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (list_empty(&cifsi->openFileList)) { 4758c2ecf20Sopenharmony_ci cifs_dbg(FYI, "closing last open instance for inode %p\n", 4768c2ecf20Sopenharmony_ci d_inode(cifs_file->dentry)); 4778c2ecf20Sopenharmony_ci /* 4788c2ecf20Sopenharmony_ci * In strict cache mode we need invalidate mapping on the last 4798c2ecf20Sopenharmony_ci * close because it may cause a error when we open this file 4808c2ecf20Sopenharmony_ci * again and get at least level II oplock. 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) 4838c2ecf20Sopenharmony_ci set_bit(CIFS_INO_INVALID_MAPPING, &cifsi->flags); 4848c2ecf20Sopenharmony_ci cifs_set_oplock_level(cifsi, 0); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci spin_unlock(&cifsi->open_file_lock); 4888c2ecf20Sopenharmony_ci spin_unlock(&tcon->open_file_lock); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci oplock_break_cancelled = wait_oplock_handler ? 4918c2ecf20Sopenharmony_ci cancel_work_sync(&cifs_file->oplock_break) : false; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (!tcon->need_reconnect && !cifs_file->invalidHandle) { 4948c2ecf20Sopenharmony_ci struct TCP_Server_Info *server = tcon->ses->server; 4958c2ecf20Sopenharmony_ci unsigned int xid; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci xid = get_xid(); 4988c2ecf20Sopenharmony_ci if (server->ops->close_getattr) 4998c2ecf20Sopenharmony_ci server->ops->close_getattr(xid, tcon, cifs_file); 5008c2ecf20Sopenharmony_ci else if (server->ops->close) 5018c2ecf20Sopenharmony_ci server->ops->close(xid, tcon, &cifs_file->fid); 5028c2ecf20Sopenharmony_ci _free_xid(xid); 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (oplock_break_cancelled) 5068c2ecf20Sopenharmony_ci cifs_done_oplock_break(cifsi); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci cifs_del_pending_open(&open); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (offload) 5118c2ecf20Sopenharmony_ci queue_work(fileinfo_put_wq, &cifs_file->put); 5128c2ecf20Sopenharmony_ci else 5138c2ecf20Sopenharmony_ci cifsFileInfo_put_final(cifs_file); 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ciint cifs_open(struct inode *inode, struct file *file) 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci int rc = -EACCES; 5208c2ecf20Sopenharmony_ci unsigned int xid; 5218c2ecf20Sopenharmony_ci __u32 oplock; 5228c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb; 5238c2ecf20Sopenharmony_ci struct TCP_Server_Info *server; 5248c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 5258c2ecf20Sopenharmony_ci struct tcon_link *tlink; 5268c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile = NULL; 5278c2ecf20Sopenharmony_ci char *full_path = NULL; 5288c2ecf20Sopenharmony_ci bool posix_open_ok = false; 5298c2ecf20Sopenharmony_ci struct cifs_fid fid; 5308c2ecf20Sopenharmony_ci struct cifs_pending_open open; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci xid = get_xid(); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci cifs_sb = CIFS_SB(inode->i_sb); 5358c2ecf20Sopenharmony_ci tlink = cifs_sb_tlink(cifs_sb); 5368c2ecf20Sopenharmony_ci if (IS_ERR(tlink)) { 5378c2ecf20Sopenharmony_ci free_xid(xid); 5388c2ecf20Sopenharmony_ci return PTR_ERR(tlink); 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci tcon = tlink_tcon(tlink); 5418c2ecf20Sopenharmony_ci server = tcon->ses->server; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci full_path = build_path_from_dentry(file_dentry(file)); 5448c2ecf20Sopenharmony_ci if (full_path == NULL) { 5458c2ecf20Sopenharmony_ci rc = -ENOMEM; 5468c2ecf20Sopenharmony_ci goto out; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci cifs_dbg(FYI, "inode = 0x%p file flags are 0x%x for %s\n", 5508c2ecf20Sopenharmony_ci inode, file->f_flags, full_path); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (file->f_flags & O_DIRECT && 5538c2ecf20Sopenharmony_ci cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO) { 5548c2ecf20Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) 5558c2ecf20Sopenharmony_ci file->f_op = &cifs_file_direct_nobrl_ops; 5568c2ecf20Sopenharmony_ci else 5578c2ecf20Sopenharmony_ci file->f_op = &cifs_file_direct_ops; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (server->oplocks) 5618c2ecf20Sopenharmony_ci oplock = REQ_OPLOCK; 5628c2ecf20Sopenharmony_ci else 5638c2ecf20Sopenharmony_ci oplock = 0; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (!tcon->broken_posix_open && tcon->unix_ext && 5668c2ecf20Sopenharmony_ci cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & 5678c2ecf20Sopenharmony_ci le64_to_cpu(tcon->fsUnixInfo.Capability))) { 5688c2ecf20Sopenharmony_ci /* can not refresh inode info since size could be stale */ 5698c2ecf20Sopenharmony_ci rc = cifs_posix_open(full_path, &inode, inode->i_sb, 5708c2ecf20Sopenharmony_ci cifs_sb->mnt_file_mode /* ignored */, 5718c2ecf20Sopenharmony_ci file->f_flags, &oplock, &fid.netfid, xid); 5728c2ecf20Sopenharmony_ci if (rc == 0) { 5738c2ecf20Sopenharmony_ci cifs_dbg(FYI, "posix open succeeded\n"); 5748c2ecf20Sopenharmony_ci posix_open_ok = true; 5758c2ecf20Sopenharmony_ci } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { 5768c2ecf20Sopenharmony_ci if (tcon->ses->serverNOS) 5778c2ecf20Sopenharmony_ci cifs_dbg(VFS, "server %s of type %s returned unexpected error on SMB posix open, disabling posix open support. Check if server update available.\n", 5788c2ecf20Sopenharmony_ci tcon->ses->serverName, 5798c2ecf20Sopenharmony_ci tcon->ses->serverNOS); 5808c2ecf20Sopenharmony_ci tcon->broken_posix_open = true; 5818c2ecf20Sopenharmony_ci } else if ((rc != -EIO) && (rc != -EREMOTE) && 5828c2ecf20Sopenharmony_ci (rc != -EOPNOTSUPP)) /* path not found or net err */ 5838c2ecf20Sopenharmony_ci goto out; 5848c2ecf20Sopenharmony_ci /* 5858c2ecf20Sopenharmony_ci * Else fallthrough to retry open the old way on network i/o 5868c2ecf20Sopenharmony_ci * or DFS errors. 5878c2ecf20Sopenharmony_ci */ 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (server->ops->get_lease_key) 5918c2ecf20Sopenharmony_ci server->ops->get_lease_key(inode, &fid); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci cifs_add_pending_open(&fid, tlink, &open); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (!posix_open_ok) { 5968c2ecf20Sopenharmony_ci if (server->ops->get_lease_key) 5978c2ecf20Sopenharmony_ci server->ops->get_lease_key(inode, &fid); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci rc = cifs_nt_open(full_path, inode, cifs_sb, tcon, 6008c2ecf20Sopenharmony_ci file->f_flags, &oplock, &fid, xid); 6018c2ecf20Sopenharmony_ci if (rc) { 6028c2ecf20Sopenharmony_ci cifs_del_pending_open(&open); 6038c2ecf20Sopenharmony_ci goto out; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci cfile = cifs_new_fileinfo(&fid, file, tlink, oplock); 6088c2ecf20Sopenharmony_ci if (cfile == NULL) { 6098c2ecf20Sopenharmony_ci if (server->ops->close) 6108c2ecf20Sopenharmony_ci server->ops->close(xid, tcon, &fid); 6118c2ecf20Sopenharmony_ci cifs_del_pending_open(&open); 6128c2ecf20Sopenharmony_ci rc = -ENOMEM; 6138c2ecf20Sopenharmony_ci goto out; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci cifs_fscache_set_inode_cookie(inode, file); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) { 6198c2ecf20Sopenharmony_ci /* 6208c2ecf20Sopenharmony_ci * Time to set mode which we can not set earlier due to 6218c2ecf20Sopenharmony_ci * problems creating new read-only files. 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ci struct cifs_unix_set_info_args args = { 6248c2ecf20Sopenharmony_ci .mode = inode->i_mode, 6258c2ecf20Sopenharmony_ci .uid = INVALID_UID, /* no change */ 6268c2ecf20Sopenharmony_ci .gid = INVALID_GID, /* no change */ 6278c2ecf20Sopenharmony_ci .ctime = NO_CHANGE_64, 6288c2ecf20Sopenharmony_ci .atime = NO_CHANGE_64, 6298c2ecf20Sopenharmony_ci .mtime = NO_CHANGE_64, 6308c2ecf20Sopenharmony_ci .device = 0, 6318c2ecf20Sopenharmony_ci }; 6328c2ecf20Sopenharmony_ci CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid.netfid, 6338c2ecf20Sopenharmony_ci cfile->pid); 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ciout: 6378c2ecf20Sopenharmony_ci kfree(full_path); 6388c2ecf20Sopenharmony_ci free_xid(xid); 6398c2ecf20Sopenharmony_ci cifs_put_tlink(tlink); 6408c2ecf20Sopenharmony_ci return rc; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic int cifs_push_posix_locks(struct cifsFileInfo *cfile); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci/* 6468c2ecf20Sopenharmony_ci * Try to reacquire byte range locks that were released when session 6478c2ecf20Sopenharmony_ci * to server was lost. 6488c2ecf20Sopenharmony_ci */ 6498c2ecf20Sopenharmony_cistatic int 6508c2ecf20Sopenharmony_cicifs_relock_file(struct cifsFileInfo *cfile) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); 6538c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); 6548c2ecf20Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 6558c2ecf20Sopenharmony_ci int rc = 0; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci down_read_nested(&cinode->lock_sem, SINGLE_DEPTH_NESTING); 6588c2ecf20Sopenharmony_ci if (cinode->can_cache_brlcks) { 6598c2ecf20Sopenharmony_ci /* can cache locks - no need to relock */ 6608c2ecf20Sopenharmony_ci up_read(&cinode->lock_sem); 6618c2ecf20Sopenharmony_ci return rc; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (cap_unix(tcon->ses) && 6658c2ecf20Sopenharmony_ci (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && 6668c2ecf20Sopenharmony_ci ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) 6678c2ecf20Sopenharmony_ci rc = cifs_push_posix_locks(cfile); 6688c2ecf20Sopenharmony_ci else 6698c2ecf20Sopenharmony_ci rc = tcon->ses->server->ops->push_mand_locks(cfile); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci up_read(&cinode->lock_sem); 6728c2ecf20Sopenharmony_ci return rc; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic int 6768c2ecf20Sopenharmony_cicifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci int rc = -EACCES; 6798c2ecf20Sopenharmony_ci unsigned int xid; 6808c2ecf20Sopenharmony_ci __u32 oplock; 6818c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb; 6828c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 6838c2ecf20Sopenharmony_ci struct TCP_Server_Info *server; 6848c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode; 6858c2ecf20Sopenharmony_ci struct inode *inode; 6868c2ecf20Sopenharmony_ci char *full_path = NULL; 6878c2ecf20Sopenharmony_ci int desired_access; 6888c2ecf20Sopenharmony_ci int disposition = FILE_OPEN; 6898c2ecf20Sopenharmony_ci int create_options = CREATE_NOT_DIR; 6908c2ecf20Sopenharmony_ci struct cifs_open_parms oparms; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci xid = get_xid(); 6938c2ecf20Sopenharmony_ci mutex_lock(&cfile->fh_mutex); 6948c2ecf20Sopenharmony_ci if (!cfile->invalidHandle) { 6958c2ecf20Sopenharmony_ci mutex_unlock(&cfile->fh_mutex); 6968c2ecf20Sopenharmony_ci rc = 0; 6978c2ecf20Sopenharmony_ci free_xid(xid); 6988c2ecf20Sopenharmony_ci return rc; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci inode = d_inode(cfile->dentry); 7028c2ecf20Sopenharmony_ci cifs_sb = CIFS_SB(inode->i_sb); 7038c2ecf20Sopenharmony_ci tcon = tlink_tcon(cfile->tlink); 7048c2ecf20Sopenharmony_ci server = tcon->ses->server; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* 7078c2ecf20Sopenharmony_ci * Can not grab rename sem here because various ops, including those 7088c2ecf20Sopenharmony_ci * that already have the rename sem can end up causing writepage to get 7098c2ecf20Sopenharmony_ci * called and if the server was down that means we end up here, and we 7108c2ecf20Sopenharmony_ci * can never tell if the caller already has the rename_sem. 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_ci full_path = build_path_from_dentry(cfile->dentry); 7138c2ecf20Sopenharmony_ci if (full_path == NULL) { 7148c2ecf20Sopenharmony_ci rc = -ENOMEM; 7158c2ecf20Sopenharmony_ci mutex_unlock(&cfile->fh_mutex); 7168c2ecf20Sopenharmony_ci free_xid(xid); 7178c2ecf20Sopenharmony_ci return rc; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci cifs_dbg(FYI, "inode = 0x%p file flags 0x%x for %s\n", 7218c2ecf20Sopenharmony_ci inode, cfile->f_flags, full_path); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (tcon->ses->server->oplocks) 7248c2ecf20Sopenharmony_ci oplock = REQ_OPLOCK; 7258c2ecf20Sopenharmony_ci else 7268c2ecf20Sopenharmony_ci oplock = 0; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (tcon->unix_ext && cap_unix(tcon->ses) && 7298c2ecf20Sopenharmony_ci (CIFS_UNIX_POSIX_PATH_OPS_CAP & 7308c2ecf20Sopenharmony_ci le64_to_cpu(tcon->fsUnixInfo.Capability))) { 7318c2ecf20Sopenharmony_ci /* 7328c2ecf20Sopenharmony_ci * O_CREAT, O_EXCL and O_TRUNC already had their effect on the 7338c2ecf20Sopenharmony_ci * original open. Must mask them off for a reopen. 7348c2ecf20Sopenharmony_ci */ 7358c2ecf20Sopenharmony_ci unsigned int oflags = cfile->f_flags & 7368c2ecf20Sopenharmony_ci ~(O_CREAT | O_EXCL | O_TRUNC); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci rc = cifs_posix_open(full_path, NULL, inode->i_sb, 7398c2ecf20Sopenharmony_ci cifs_sb->mnt_file_mode /* ignored */, 7408c2ecf20Sopenharmony_ci oflags, &oplock, &cfile->fid.netfid, xid); 7418c2ecf20Sopenharmony_ci if (rc == 0) { 7428c2ecf20Sopenharmony_ci cifs_dbg(FYI, "posix reopen succeeded\n"); 7438c2ecf20Sopenharmony_ci oparms.reconnect = true; 7448c2ecf20Sopenharmony_ci goto reopen_success; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci /* 7478c2ecf20Sopenharmony_ci * fallthrough to retry open the old way on errors, especially 7488c2ecf20Sopenharmony_ci * in the reconnect path it is important to retry hard 7498c2ecf20Sopenharmony_ci */ 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci desired_access = cifs_convert_flags(cfile->f_flags); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* O_SYNC also has bit for O_DSYNC so following check picks up either */ 7558c2ecf20Sopenharmony_ci if (cfile->f_flags & O_SYNC) 7568c2ecf20Sopenharmony_ci create_options |= CREATE_WRITE_THROUGH; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (cfile->f_flags & O_DIRECT) 7598c2ecf20Sopenharmony_ci create_options |= CREATE_NO_BUFFER; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (server->ops->get_lease_key) 7628c2ecf20Sopenharmony_ci server->ops->get_lease_key(inode, &cfile->fid); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci oparms.tcon = tcon; 7658c2ecf20Sopenharmony_ci oparms.cifs_sb = cifs_sb; 7668c2ecf20Sopenharmony_ci oparms.desired_access = desired_access; 7678c2ecf20Sopenharmony_ci oparms.create_options = cifs_create_options(cifs_sb, create_options); 7688c2ecf20Sopenharmony_ci oparms.disposition = disposition; 7698c2ecf20Sopenharmony_ci oparms.path = full_path; 7708c2ecf20Sopenharmony_ci oparms.fid = &cfile->fid; 7718c2ecf20Sopenharmony_ci oparms.reconnect = true; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* 7748c2ecf20Sopenharmony_ci * Can not refresh inode by passing in file_info buf to be returned by 7758c2ecf20Sopenharmony_ci * ops->open and then calling get_inode_info with returned buf since 7768c2ecf20Sopenharmony_ci * file might have write behind data that needs to be flushed and server 7778c2ecf20Sopenharmony_ci * version of file size can be stale. If we knew for sure that inode was 7788c2ecf20Sopenharmony_ci * not dirty locally we could do this. 7798c2ecf20Sopenharmony_ci */ 7808c2ecf20Sopenharmony_ci rc = server->ops->open(xid, &oparms, &oplock, NULL); 7818c2ecf20Sopenharmony_ci if (rc == -ENOENT && oparms.reconnect == false) { 7828c2ecf20Sopenharmony_ci /* durable handle timeout is expired - open the file again */ 7838c2ecf20Sopenharmony_ci rc = server->ops->open(xid, &oparms, &oplock, NULL); 7848c2ecf20Sopenharmony_ci /* indicate that we need to relock the file */ 7858c2ecf20Sopenharmony_ci oparms.reconnect = true; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (rc) { 7898c2ecf20Sopenharmony_ci mutex_unlock(&cfile->fh_mutex); 7908c2ecf20Sopenharmony_ci cifs_dbg(FYI, "cifs_reopen returned 0x%x\n", rc); 7918c2ecf20Sopenharmony_ci cifs_dbg(FYI, "oplock: %d\n", oplock); 7928c2ecf20Sopenharmony_ci goto reopen_error_exit; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_cireopen_success: 7968c2ecf20Sopenharmony_ci cfile->invalidHandle = false; 7978c2ecf20Sopenharmony_ci mutex_unlock(&cfile->fh_mutex); 7988c2ecf20Sopenharmony_ci cinode = CIFS_I(inode); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (can_flush) { 8018c2ecf20Sopenharmony_ci rc = filemap_write_and_wait(inode->i_mapping); 8028c2ecf20Sopenharmony_ci if (!is_interrupt_error(rc)) 8038c2ecf20Sopenharmony_ci mapping_set_error(inode->i_mapping, rc); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if (tcon->posix_extensions) 8068c2ecf20Sopenharmony_ci rc = smb311_posix_get_inode_info(&inode, full_path, inode->i_sb, xid); 8078c2ecf20Sopenharmony_ci else if (tcon->unix_ext) 8088c2ecf20Sopenharmony_ci rc = cifs_get_inode_info_unix(&inode, full_path, 8098c2ecf20Sopenharmony_ci inode->i_sb, xid); 8108c2ecf20Sopenharmony_ci else 8118c2ecf20Sopenharmony_ci rc = cifs_get_inode_info(&inode, full_path, NULL, 8128c2ecf20Sopenharmony_ci inode->i_sb, xid, NULL); 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci /* 8158c2ecf20Sopenharmony_ci * Else we are writing out data to server already and could deadlock if 8168c2ecf20Sopenharmony_ci * we tried to flush data, and since we do not know if we have data that 8178c2ecf20Sopenharmony_ci * would invalidate the current end of file on the server we can not go 8188c2ecf20Sopenharmony_ci * to the server to get the new inode info. 8198c2ecf20Sopenharmony_ci */ 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci /* 8228c2ecf20Sopenharmony_ci * If the server returned a read oplock and we have mandatory brlocks, 8238c2ecf20Sopenharmony_ci * set oplock level to None. 8248c2ecf20Sopenharmony_ci */ 8258c2ecf20Sopenharmony_ci if (server->ops->is_read_op(oplock) && cifs_has_mand_locks(cinode)) { 8268c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Reset oplock val from read to None due to mand locks\n"); 8278c2ecf20Sopenharmony_ci oplock = 0; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci server->ops->set_fid(cfile, &cfile->fid, oplock); 8318c2ecf20Sopenharmony_ci if (oparms.reconnect) 8328c2ecf20Sopenharmony_ci cifs_relock_file(cfile); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cireopen_error_exit: 8358c2ecf20Sopenharmony_ci kfree(full_path); 8368c2ecf20Sopenharmony_ci free_xid(xid); 8378c2ecf20Sopenharmony_ci return rc; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ciint cifs_close(struct inode *inode, struct file *file) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci if (file->private_data != NULL) { 8438c2ecf20Sopenharmony_ci _cifsFileInfo_put(file->private_data, true, false); 8448c2ecf20Sopenharmony_ci file->private_data = NULL; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* return code from the ->release op is always ignored */ 8488c2ecf20Sopenharmony_ci return 0; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_civoid 8528c2ecf20Sopenharmony_cicifs_reopen_persistent_handles(struct cifs_tcon *tcon) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci struct cifsFileInfo *open_file; 8558c2ecf20Sopenharmony_ci struct list_head *tmp; 8568c2ecf20Sopenharmony_ci struct list_head *tmp1; 8578c2ecf20Sopenharmony_ci struct list_head tmp_list; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (!tcon->use_persistent || !tcon->need_reopen_files) 8608c2ecf20Sopenharmony_ci return; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci tcon->need_reopen_files = false; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Reopen persistent handles\n"); 8658c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tmp_list); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci /* list all files open on tree connection, reopen resilient handles */ 8688c2ecf20Sopenharmony_ci spin_lock(&tcon->open_file_lock); 8698c2ecf20Sopenharmony_ci list_for_each(tmp, &tcon->openFileList) { 8708c2ecf20Sopenharmony_ci open_file = list_entry(tmp, struct cifsFileInfo, tlist); 8718c2ecf20Sopenharmony_ci if (!open_file->invalidHandle) 8728c2ecf20Sopenharmony_ci continue; 8738c2ecf20Sopenharmony_ci cifsFileInfo_get(open_file); 8748c2ecf20Sopenharmony_ci list_add_tail(&open_file->rlist, &tmp_list); 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci spin_unlock(&tcon->open_file_lock); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci list_for_each_safe(tmp, tmp1, &tmp_list) { 8798c2ecf20Sopenharmony_ci open_file = list_entry(tmp, struct cifsFileInfo, rlist); 8808c2ecf20Sopenharmony_ci if (cifs_reopen_file(open_file, false /* do not flush */)) 8818c2ecf20Sopenharmony_ci tcon->need_reopen_files = true; 8828c2ecf20Sopenharmony_ci list_del_init(&open_file->rlist); 8838c2ecf20Sopenharmony_ci cifsFileInfo_put(open_file); 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ciint cifs_closedir(struct inode *inode, struct file *file) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci int rc = 0; 8908c2ecf20Sopenharmony_ci unsigned int xid; 8918c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile = file->private_data; 8928c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 8938c2ecf20Sopenharmony_ci struct TCP_Server_Info *server; 8948c2ecf20Sopenharmony_ci char *buf; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Closedir inode = 0x%p\n", inode); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (cfile == NULL) 8998c2ecf20Sopenharmony_ci return rc; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci xid = get_xid(); 9028c2ecf20Sopenharmony_ci tcon = tlink_tcon(cfile->tlink); 9038c2ecf20Sopenharmony_ci server = tcon->ses->server; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Freeing private data in close dir\n"); 9068c2ecf20Sopenharmony_ci spin_lock(&cfile->file_info_lock); 9078c2ecf20Sopenharmony_ci if (server->ops->dir_needs_close(cfile)) { 9088c2ecf20Sopenharmony_ci cfile->invalidHandle = true; 9098c2ecf20Sopenharmony_ci spin_unlock(&cfile->file_info_lock); 9108c2ecf20Sopenharmony_ci if (server->ops->close_dir) 9118c2ecf20Sopenharmony_ci rc = server->ops->close_dir(xid, tcon, &cfile->fid); 9128c2ecf20Sopenharmony_ci else 9138c2ecf20Sopenharmony_ci rc = -ENOSYS; 9148c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Closing uncompleted readdir with rc %d\n", rc); 9158c2ecf20Sopenharmony_ci /* not much we can do if it fails anyway, ignore rc */ 9168c2ecf20Sopenharmony_ci rc = 0; 9178c2ecf20Sopenharmony_ci } else 9188c2ecf20Sopenharmony_ci spin_unlock(&cfile->file_info_lock); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci buf = cfile->srch_inf.ntwrk_buf_start; 9218c2ecf20Sopenharmony_ci if (buf) { 9228c2ecf20Sopenharmony_ci cifs_dbg(FYI, "closedir free smb buf in srch struct\n"); 9238c2ecf20Sopenharmony_ci cfile->srch_inf.ntwrk_buf_start = NULL; 9248c2ecf20Sopenharmony_ci if (cfile->srch_inf.smallBuf) 9258c2ecf20Sopenharmony_ci cifs_small_buf_release(buf); 9268c2ecf20Sopenharmony_ci else 9278c2ecf20Sopenharmony_ci cifs_buf_release(buf); 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci cifs_put_tlink(cfile->tlink); 9318c2ecf20Sopenharmony_ci kfree(file->private_data); 9328c2ecf20Sopenharmony_ci file->private_data = NULL; 9338c2ecf20Sopenharmony_ci /* BB can we lock the filestruct while this is going on? */ 9348c2ecf20Sopenharmony_ci free_xid(xid); 9358c2ecf20Sopenharmony_ci return rc; 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic struct cifsLockInfo * 9398c2ecf20Sopenharmony_cicifs_lock_init(__u64 offset, __u64 length, __u8 type, __u16 flags) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci struct cifsLockInfo *lock = 9428c2ecf20Sopenharmony_ci kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL); 9438c2ecf20Sopenharmony_ci if (!lock) 9448c2ecf20Sopenharmony_ci return lock; 9458c2ecf20Sopenharmony_ci lock->offset = offset; 9468c2ecf20Sopenharmony_ci lock->length = length; 9478c2ecf20Sopenharmony_ci lock->type = type; 9488c2ecf20Sopenharmony_ci lock->pid = current->tgid; 9498c2ecf20Sopenharmony_ci lock->flags = flags; 9508c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&lock->blist); 9518c2ecf20Sopenharmony_ci init_waitqueue_head(&lock->block_q); 9528c2ecf20Sopenharmony_ci return lock; 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_civoid 9568c2ecf20Sopenharmony_cicifs_del_lock_waiters(struct cifsLockInfo *lock) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci struct cifsLockInfo *li, *tmp; 9598c2ecf20Sopenharmony_ci list_for_each_entry_safe(li, tmp, &lock->blist, blist) { 9608c2ecf20Sopenharmony_ci list_del_init(&li->blist); 9618c2ecf20Sopenharmony_ci wake_up(&li->block_q); 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci} 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci#define CIFS_LOCK_OP 0 9668c2ecf20Sopenharmony_ci#define CIFS_READ_OP 1 9678c2ecf20Sopenharmony_ci#define CIFS_WRITE_OP 2 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci/* @rw_check : 0 - no op, 1 - read, 2 - write */ 9708c2ecf20Sopenharmony_cistatic bool 9718c2ecf20Sopenharmony_cicifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, 9728c2ecf20Sopenharmony_ci __u64 length, __u8 type, __u16 flags, 9738c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile, 9748c2ecf20Sopenharmony_ci struct cifsLockInfo **conf_lock, int rw_check) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci struct cifsLockInfo *li; 9778c2ecf20Sopenharmony_ci struct cifsFileInfo *cur_cfile = fdlocks->cfile; 9788c2ecf20Sopenharmony_ci struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci list_for_each_entry(li, &fdlocks->locks, llist) { 9818c2ecf20Sopenharmony_ci if (offset + length <= li->offset || 9828c2ecf20Sopenharmony_ci offset >= li->offset + li->length) 9838c2ecf20Sopenharmony_ci continue; 9848c2ecf20Sopenharmony_ci if (rw_check != CIFS_LOCK_OP && current->tgid == li->pid && 9858c2ecf20Sopenharmony_ci server->ops->compare_fids(cfile, cur_cfile)) { 9868c2ecf20Sopenharmony_ci /* shared lock prevents write op through the same fid */ 9878c2ecf20Sopenharmony_ci if (!(li->type & server->vals->shared_lock_type) || 9888c2ecf20Sopenharmony_ci rw_check != CIFS_WRITE_OP) 9898c2ecf20Sopenharmony_ci continue; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci if ((type & server->vals->shared_lock_type) && 9928c2ecf20Sopenharmony_ci ((server->ops->compare_fids(cfile, cur_cfile) && 9938c2ecf20Sopenharmony_ci current->tgid == li->pid) || type == li->type)) 9948c2ecf20Sopenharmony_ci continue; 9958c2ecf20Sopenharmony_ci if (rw_check == CIFS_LOCK_OP && 9968c2ecf20Sopenharmony_ci (flags & FL_OFDLCK) && (li->flags & FL_OFDLCK) && 9978c2ecf20Sopenharmony_ci server->ops->compare_fids(cfile, cur_cfile)) 9988c2ecf20Sopenharmony_ci continue; 9998c2ecf20Sopenharmony_ci if (conf_lock) 10008c2ecf20Sopenharmony_ci *conf_lock = li; 10018c2ecf20Sopenharmony_ci return true; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci return false; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_cibool 10078c2ecf20Sopenharmony_cicifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, __u64 length, 10088c2ecf20Sopenharmony_ci __u8 type, __u16 flags, 10098c2ecf20Sopenharmony_ci struct cifsLockInfo **conf_lock, int rw_check) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci bool rc = false; 10128c2ecf20Sopenharmony_ci struct cifs_fid_locks *cur; 10138c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci list_for_each_entry(cur, &cinode->llist, llist) { 10168c2ecf20Sopenharmony_ci rc = cifs_find_fid_lock_conflict(cur, offset, length, type, 10178c2ecf20Sopenharmony_ci flags, cfile, conf_lock, 10188c2ecf20Sopenharmony_ci rw_check); 10198c2ecf20Sopenharmony_ci if (rc) 10208c2ecf20Sopenharmony_ci break; 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci return rc; 10248c2ecf20Sopenharmony_ci} 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci/* 10278c2ecf20Sopenharmony_ci * Check if there is another lock that prevents us to set the lock (mandatory 10288c2ecf20Sopenharmony_ci * style). If such a lock exists, update the flock structure with its 10298c2ecf20Sopenharmony_ci * properties. Otherwise, set the flock type to F_UNLCK if we can cache brlocks 10308c2ecf20Sopenharmony_ci * or leave it the same if we can't. Returns 0 if we don't need to request to 10318c2ecf20Sopenharmony_ci * the server or 1 otherwise. 10328c2ecf20Sopenharmony_ci */ 10338c2ecf20Sopenharmony_cistatic int 10348c2ecf20Sopenharmony_cicifs_lock_test(struct cifsFileInfo *cfile, __u64 offset, __u64 length, 10358c2ecf20Sopenharmony_ci __u8 type, struct file_lock *flock) 10368c2ecf20Sopenharmony_ci{ 10378c2ecf20Sopenharmony_ci int rc = 0; 10388c2ecf20Sopenharmony_ci struct cifsLockInfo *conf_lock; 10398c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); 10408c2ecf20Sopenharmony_ci struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; 10418c2ecf20Sopenharmony_ci bool exist; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci down_read(&cinode->lock_sem); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci exist = cifs_find_lock_conflict(cfile, offset, length, type, 10468c2ecf20Sopenharmony_ci flock->fl_flags, &conf_lock, 10478c2ecf20Sopenharmony_ci CIFS_LOCK_OP); 10488c2ecf20Sopenharmony_ci if (exist) { 10498c2ecf20Sopenharmony_ci flock->fl_start = conf_lock->offset; 10508c2ecf20Sopenharmony_ci flock->fl_end = conf_lock->offset + conf_lock->length - 1; 10518c2ecf20Sopenharmony_ci flock->fl_pid = conf_lock->pid; 10528c2ecf20Sopenharmony_ci if (conf_lock->type & server->vals->shared_lock_type) 10538c2ecf20Sopenharmony_ci flock->fl_type = F_RDLCK; 10548c2ecf20Sopenharmony_ci else 10558c2ecf20Sopenharmony_ci flock->fl_type = F_WRLCK; 10568c2ecf20Sopenharmony_ci } else if (!cinode->can_cache_brlcks) 10578c2ecf20Sopenharmony_ci rc = 1; 10588c2ecf20Sopenharmony_ci else 10598c2ecf20Sopenharmony_ci flock->fl_type = F_UNLCK; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci up_read(&cinode->lock_sem); 10628c2ecf20Sopenharmony_ci return rc; 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_cistatic void 10668c2ecf20Sopenharmony_cicifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock) 10678c2ecf20Sopenharmony_ci{ 10688c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); 10698c2ecf20Sopenharmony_ci cifs_down_write(&cinode->lock_sem); 10708c2ecf20Sopenharmony_ci list_add_tail(&lock->llist, &cfile->llist->locks); 10718c2ecf20Sopenharmony_ci up_write(&cinode->lock_sem); 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci/* 10758c2ecf20Sopenharmony_ci * Set the byte-range lock (mandatory style). Returns: 10768c2ecf20Sopenharmony_ci * 1) 0, if we set the lock and don't need to request to the server; 10778c2ecf20Sopenharmony_ci * 2) 1, if no locks prevent us but we need to request to the server; 10788c2ecf20Sopenharmony_ci * 3) -EACCES, if there is a lock that prevents us and wait is false. 10798c2ecf20Sopenharmony_ci */ 10808c2ecf20Sopenharmony_cistatic int 10818c2ecf20Sopenharmony_cicifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock, 10828c2ecf20Sopenharmony_ci bool wait) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci struct cifsLockInfo *conf_lock; 10858c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); 10868c2ecf20Sopenharmony_ci bool exist; 10878c2ecf20Sopenharmony_ci int rc = 0; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_citry_again: 10908c2ecf20Sopenharmony_ci exist = false; 10918c2ecf20Sopenharmony_ci cifs_down_write(&cinode->lock_sem); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci exist = cifs_find_lock_conflict(cfile, lock->offset, lock->length, 10948c2ecf20Sopenharmony_ci lock->type, lock->flags, &conf_lock, 10958c2ecf20Sopenharmony_ci CIFS_LOCK_OP); 10968c2ecf20Sopenharmony_ci if (!exist && cinode->can_cache_brlcks) { 10978c2ecf20Sopenharmony_ci list_add_tail(&lock->llist, &cfile->llist->locks); 10988c2ecf20Sopenharmony_ci up_write(&cinode->lock_sem); 10998c2ecf20Sopenharmony_ci return rc; 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci if (!exist) 11038c2ecf20Sopenharmony_ci rc = 1; 11048c2ecf20Sopenharmony_ci else if (!wait) 11058c2ecf20Sopenharmony_ci rc = -EACCES; 11068c2ecf20Sopenharmony_ci else { 11078c2ecf20Sopenharmony_ci list_add_tail(&lock->blist, &conf_lock->blist); 11088c2ecf20Sopenharmony_ci up_write(&cinode->lock_sem); 11098c2ecf20Sopenharmony_ci rc = wait_event_interruptible(lock->block_q, 11108c2ecf20Sopenharmony_ci (lock->blist.prev == &lock->blist) && 11118c2ecf20Sopenharmony_ci (lock->blist.next == &lock->blist)); 11128c2ecf20Sopenharmony_ci if (!rc) 11138c2ecf20Sopenharmony_ci goto try_again; 11148c2ecf20Sopenharmony_ci cifs_down_write(&cinode->lock_sem); 11158c2ecf20Sopenharmony_ci list_del_init(&lock->blist); 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci up_write(&cinode->lock_sem); 11198c2ecf20Sopenharmony_ci return rc; 11208c2ecf20Sopenharmony_ci} 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci/* 11238c2ecf20Sopenharmony_ci * Check if there is another lock that prevents us to set the lock (posix 11248c2ecf20Sopenharmony_ci * style). If such a lock exists, update the flock structure with its 11258c2ecf20Sopenharmony_ci * properties. Otherwise, set the flock type to F_UNLCK if we can cache brlocks 11268c2ecf20Sopenharmony_ci * or leave it the same if we can't. Returns 0 if we don't need to request to 11278c2ecf20Sopenharmony_ci * the server or 1 otherwise. 11288c2ecf20Sopenharmony_ci */ 11298c2ecf20Sopenharmony_cistatic int 11308c2ecf20Sopenharmony_cicifs_posix_lock_test(struct file *file, struct file_lock *flock) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci int rc = 0; 11338c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(file_inode(file)); 11348c2ecf20Sopenharmony_ci unsigned char saved_type = flock->fl_type; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if ((flock->fl_flags & FL_POSIX) == 0) 11378c2ecf20Sopenharmony_ci return 1; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci down_read(&cinode->lock_sem); 11408c2ecf20Sopenharmony_ci posix_test_lock(file, flock); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (flock->fl_type == F_UNLCK && !cinode->can_cache_brlcks) { 11438c2ecf20Sopenharmony_ci flock->fl_type = saved_type; 11448c2ecf20Sopenharmony_ci rc = 1; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci up_read(&cinode->lock_sem); 11488c2ecf20Sopenharmony_ci return rc; 11498c2ecf20Sopenharmony_ci} 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci/* 11528c2ecf20Sopenharmony_ci * Set the byte-range lock (posix style). Returns: 11538c2ecf20Sopenharmony_ci * 1) <0, if the error occurs while setting the lock; 11548c2ecf20Sopenharmony_ci * 2) 0, if we set the lock and don't need to request to the server; 11558c2ecf20Sopenharmony_ci * 3) FILE_LOCK_DEFERRED, if we will wait for some other file_lock; 11568c2ecf20Sopenharmony_ci * 4) FILE_LOCK_DEFERRED + 1, if we need to request to the server. 11578c2ecf20Sopenharmony_ci */ 11588c2ecf20Sopenharmony_cistatic int 11598c2ecf20Sopenharmony_cicifs_posix_lock_set(struct file *file, struct file_lock *flock) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(file_inode(file)); 11628c2ecf20Sopenharmony_ci int rc = FILE_LOCK_DEFERRED + 1; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci if ((flock->fl_flags & FL_POSIX) == 0) 11658c2ecf20Sopenharmony_ci return rc; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci cifs_down_write(&cinode->lock_sem); 11688c2ecf20Sopenharmony_ci if (!cinode->can_cache_brlcks) { 11698c2ecf20Sopenharmony_ci up_write(&cinode->lock_sem); 11708c2ecf20Sopenharmony_ci return rc; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci rc = posix_lock_file(file, flock, NULL); 11748c2ecf20Sopenharmony_ci up_write(&cinode->lock_sem); 11758c2ecf20Sopenharmony_ci return rc; 11768c2ecf20Sopenharmony_ci} 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ciint 11798c2ecf20Sopenharmony_cicifs_push_mandatory_locks(struct cifsFileInfo *cfile) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci unsigned int xid; 11828c2ecf20Sopenharmony_ci int rc = 0, stored_rc; 11838c2ecf20Sopenharmony_ci struct cifsLockInfo *li, *tmp; 11848c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 11858c2ecf20Sopenharmony_ci unsigned int num, max_num, max_buf; 11868c2ecf20Sopenharmony_ci LOCKING_ANDX_RANGE *buf, *cur; 11878c2ecf20Sopenharmony_ci static const int types[] = { 11888c2ecf20Sopenharmony_ci LOCKING_ANDX_LARGE_FILES, 11898c2ecf20Sopenharmony_ci LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES 11908c2ecf20Sopenharmony_ci }; 11918c2ecf20Sopenharmony_ci int i; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci xid = get_xid(); 11948c2ecf20Sopenharmony_ci tcon = tlink_tcon(cfile->tlink); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* 11978c2ecf20Sopenharmony_ci * Accessing maxBuf is racy with cifs_reconnect - need to store value 11988c2ecf20Sopenharmony_ci * and check it before using. 11998c2ecf20Sopenharmony_ci */ 12008c2ecf20Sopenharmony_ci max_buf = tcon->ses->server->maxBuf; 12018c2ecf20Sopenharmony_ci if (max_buf < (sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE))) { 12028c2ecf20Sopenharmony_ci free_xid(xid); 12038c2ecf20Sopenharmony_ci return -EINVAL; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) > 12078c2ecf20Sopenharmony_ci PAGE_SIZE); 12088c2ecf20Sopenharmony_ci max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr), 12098c2ecf20Sopenharmony_ci PAGE_SIZE); 12108c2ecf20Sopenharmony_ci max_num = (max_buf - sizeof(struct smb_hdr)) / 12118c2ecf20Sopenharmony_ci sizeof(LOCKING_ANDX_RANGE); 12128c2ecf20Sopenharmony_ci buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); 12138c2ecf20Sopenharmony_ci if (!buf) { 12148c2ecf20Sopenharmony_ci free_xid(xid); 12158c2ecf20Sopenharmony_ci return -ENOMEM; 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 12198c2ecf20Sopenharmony_ci cur = buf; 12208c2ecf20Sopenharmony_ci num = 0; 12218c2ecf20Sopenharmony_ci list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) { 12228c2ecf20Sopenharmony_ci if (li->type != types[i]) 12238c2ecf20Sopenharmony_ci continue; 12248c2ecf20Sopenharmony_ci cur->Pid = cpu_to_le16(li->pid); 12258c2ecf20Sopenharmony_ci cur->LengthLow = cpu_to_le32((u32)li->length); 12268c2ecf20Sopenharmony_ci cur->LengthHigh = cpu_to_le32((u32)(li->length>>32)); 12278c2ecf20Sopenharmony_ci cur->OffsetLow = cpu_to_le32((u32)li->offset); 12288c2ecf20Sopenharmony_ci cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32)); 12298c2ecf20Sopenharmony_ci if (++num == max_num) { 12308c2ecf20Sopenharmony_ci stored_rc = cifs_lockv(xid, tcon, 12318c2ecf20Sopenharmony_ci cfile->fid.netfid, 12328c2ecf20Sopenharmony_ci (__u8)li->type, 0, num, 12338c2ecf20Sopenharmony_ci buf); 12348c2ecf20Sopenharmony_ci if (stored_rc) 12358c2ecf20Sopenharmony_ci rc = stored_rc; 12368c2ecf20Sopenharmony_ci cur = buf; 12378c2ecf20Sopenharmony_ci num = 0; 12388c2ecf20Sopenharmony_ci } else 12398c2ecf20Sopenharmony_ci cur++; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci if (num) { 12438c2ecf20Sopenharmony_ci stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid, 12448c2ecf20Sopenharmony_ci (__u8)types[i], 0, num, buf); 12458c2ecf20Sopenharmony_ci if (stored_rc) 12468c2ecf20Sopenharmony_ci rc = stored_rc; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci kfree(buf); 12518c2ecf20Sopenharmony_ci free_xid(xid); 12528c2ecf20Sopenharmony_ci return rc; 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic __u32 12568c2ecf20Sopenharmony_cihash_lockowner(fl_owner_t owner) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci return cifs_lock_secret ^ hash32_ptr((const void *)owner); 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistruct lock_to_push { 12628c2ecf20Sopenharmony_ci struct list_head llist; 12638c2ecf20Sopenharmony_ci __u64 offset; 12648c2ecf20Sopenharmony_ci __u64 length; 12658c2ecf20Sopenharmony_ci __u32 pid; 12668c2ecf20Sopenharmony_ci __u16 netfid; 12678c2ecf20Sopenharmony_ci __u8 type; 12688c2ecf20Sopenharmony_ci}; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_cistatic int 12718c2ecf20Sopenharmony_cicifs_push_posix_locks(struct cifsFileInfo *cfile) 12728c2ecf20Sopenharmony_ci{ 12738c2ecf20Sopenharmony_ci struct inode *inode = d_inode(cfile->dentry); 12748c2ecf20Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 12758c2ecf20Sopenharmony_ci struct file_lock *flock; 12768c2ecf20Sopenharmony_ci struct file_lock_context *flctx = inode->i_flctx; 12778c2ecf20Sopenharmony_ci unsigned int count = 0, i; 12788c2ecf20Sopenharmony_ci int rc = 0, xid, type; 12798c2ecf20Sopenharmony_ci struct list_head locks_to_send, *el; 12808c2ecf20Sopenharmony_ci struct lock_to_push *lck, *tmp; 12818c2ecf20Sopenharmony_ci __u64 length; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci xid = get_xid(); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci if (!flctx) 12868c2ecf20Sopenharmony_ci goto out; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci spin_lock(&flctx->flc_lock); 12898c2ecf20Sopenharmony_ci list_for_each(el, &flctx->flc_posix) { 12908c2ecf20Sopenharmony_ci count++; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci spin_unlock(&flctx->flc_lock); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&locks_to_send); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci /* 12978c2ecf20Sopenharmony_ci * Allocating count locks is enough because no FL_POSIX locks can be 12988c2ecf20Sopenharmony_ci * added to the list while we are holding cinode->lock_sem that 12998c2ecf20Sopenharmony_ci * protects locking operations of this inode. 13008c2ecf20Sopenharmony_ci */ 13018c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 13028c2ecf20Sopenharmony_ci lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL); 13038c2ecf20Sopenharmony_ci if (!lck) { 13048c2ecf20Sopenharmony_ci rc = -ENOMEM; 13058c2ecf20Sopenharmony_ci goto err_out; 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci list_add_tail(&lck->llist, &locks_to_send); 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci el = locks_to_send.next; 13118c2ecf20Sopenharmony_ci spin_lock(&flctx->flc_lock); 13128c2ecf20Sopenharmony_ci list_for_each_entry(flock, &flctx->flc_posix, fl_list) { 13138c2ecf20Sopenharmony_ci if (el == &locks_to_send) { 13148c2ecf20Sopenharmony_ci /* 13158c2ecf20Sopenharmony_ci * The list ended. We don't have enough allocated 13168c2ecf20Sopenharmony_ci * structures - something is really wrong. 13178c2ecf20Sopenharmony_ci */ 13188c2ecf20Sopenharmony_ci cifs_dbg(VFS, "Can't push all brlocks!\n"); 13198c2ecf20Sopenharmony_ci break; 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci length = 1 + flock->fl_end - flock->fl_start; 13228c2ecf20Sopenharmony_ci if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK) 13238c2ecf20Sopenharmony_ci type = CIFS_RDLCK; 13248c2ecf20Sopenharmony_ci else 13258c2ecf20Sopenharmony_ci type = CIFS_WRLCK; 13268c2ecf20Sopenharmony_ci lck = list_entry(el, struct lock_to_push, llist); 13278c2ecf20Sopenharmony_ci lck->pid = hash_lockowner(flock->fl_owner); 13288c2ecf20Sopenharmony_ci lck->netfid = cfile->fid.netfid; 13298c2ecf20Sopenharmony_ci lck->length = length; 13308c2ecf20Sopenharmony_ci lck->type = type; 13318c2ecf20Sopenharmony_ci lck->offset = flock->fl_start; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci spin_unlock(&flctx->flc_lock); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) { 13368c2ecf20Sopenharmony_ci int stored_rc; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci stored_rc = CIFSSMBPosixLock(xid, tcon, lck->netfid, lck->pid, 13398c2ecf20Sopenharmony_ci lck->offset, lck->length, NULL, 13408c2ecf20Sopenharmony_ci lck->type, 0); 13418c2ecf20Sopenharmony_ci if (stored_rc) 13428c2ecf20Sopenharmony_ci rc = stored_rc; 13438c2ecf20Sopenharmony_ci list_del(&lck->llist); 13448c2ecf20Sopenharmony_ci kfree(lck); 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ciout: 13488c2ecf20Sopenharmony_ci free_xid(xid); 13498c2ecf20Sopenharmony_ci return rc; 13508c2ecf20Sopenharmony_cierr_out: 13518c2ecf20Sopenharmony_ci list_for_each_entry_safe(lck, tmp, &locks_to_send, llist) { 13528c2ecf20Sopenharmony_ci list_del(&lck->llist); 13538c2ecf20Sopenharmony_ci kfree(lck); 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci goto out; 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_cistatic int 13598c2ecf20Sopenharmony_cicifs_push_locks(struct cifsFileInfo *cfile) 13608c2ecf20Sopenharmony_ci{ 13618c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); 13628c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); 13638c2ecf20Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 13648c2ecf20Sopenharmony_ci int rc = 0; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci /* we are going to update can_cache_brlcks here - need a write access */ 13678c2ecf20Sopenharmony_ci cifs_down_write(&cinode->lock_sem); 13688c2ecf20Sopenharmony_ci if (!cinode->can_cache_brlcks) { 13698c2ecf20Sopenharmony_ci up_write(&cinode->lock_sem); 13708c2ecf20Sopenharmony_ci return rc; 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci if (cap_unix(tcon->ses) && 13748c2ecf20Sopenharmony_ci (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && 13758c2ecf20Sopenharmony_ci ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) 13768c2ecf20Sopenharmony_ci rc = cifs_push_posix_locks(cfile); 13778c2ecf20Sopenharmony_ci else 13788c2ecf20Sopenharmony_ci rc = tcon->ses->server->ops->push_mand_locks(cfile); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci cinode->can_cache_brlcks = false; 13818c2ecf20Sopenharmony_ci up_write(&cinode->lock_sem); 13828c2ecf20Sopenharmony_ci return rc; 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_cistatic void 13868c2ecf20Sopenharmony_cicifs_read_flock(struct file_lock *flock, __u32 *type, int *lock, int *unlock, 13878c2ecf20Sopenharmony_ci bool *wait_flag, struct TCP_Server_Info *server) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci if (flock->fl_flags & FL_POSIX) 13908c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Posix\n"); 13918c2ecf20Sopenharmony_ci if (flock->fl_flags & FL_FLOCK) 13928c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Flock\n"); 13938c2ecf20Sopenharmony_ci if (flock->fl_flags & FL_SLEEP) { 13948c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Blocking lock\n"); 13958c2ecf20Sopenharmony_ci *wait_flag = true; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci if (flock->fl_flags & FL_ACCESS) 13988c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Process suspended by mandatory locking - not implemented yet\n"); 13998c2ecf20Sopenharmony_ci if (flock->fl_flags & FL_LEASE) 14008c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Lease on file - not implemented yet\n"); 14018c2ecf20Sopenharmony_ci if (flock->fl_flags & 14028c2ecf20Sopenharmony_ci (~(FL_POSIX | FL_FLOCK | FL_SLEEP | 14038c2ecf20Sopenharmony_ci FL_ACCESS | FL_LEASE | FL_CLOSE | FL_OFDLCK))) 14048c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Unknown lock flags 0x%x\n", flock->fl_flags); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci *type = server->vals->large_lock_type; 14078c2ecf20Sopenharmony_ci if (flock->fl_type == F_WRLCK) { 14088c2ecf20Sopenharmony_ci cifs_dbg(FYI, "F_WRLCK\n"); 14098c2ecf20Sopenharmony_ci *type |= server->vals->exclusive_lock_type; 14108c2ecf20Sopenharmony_ci *lock = 1; 14118c2ecf20Sopenharmony_ci } else if (flock->fl_type == F_UNLCK) { 14128c2ecf20Sopenharmony_ci cifs_dbg(FYI, "F_UNLCK\n"); 14138c2ecf20Sopenharmony_ci *type |= server->vals->unlock_lock_type; 14148c2ecf20Sopenharmony_ci *unlock = 1; 14158c2ecf20Sopenharmony_ci /* Check if unlock includes more than one lock range */ 14168c2ecf20Sopenharmony_ci } else if (flock->fl_type == F_RDLCK) { 14178c2ecf20Sopenharmony_ci cifs_dbg(FYI, "F_RDLCK\n"); 14188c2ecf20Sopenharmony_ci *type |= server->vals->shared_lock_type; 14198c2ecf20Sopenharmony_ci *lock = 1; 14208c2ecf20Sopenharmony_ci } else if (flock->fl_type == F_EXLCK) { 14218c2ecf20Sopenharmony_ci cifs_dbg(FYI, "F_EXLCK\n"); 14228c2ecf20Sopenharmony_ci *type |= server->vals->exclusive_lock_type; 14238c2ecf20Sopenharmony_ci *lock = 1; 14248c2ecf20Sopenharmony_ci } else if (flock->fl_type == F_SHLCK) { 14258c2ecf20Sopenharmony_ci cifs_dbg(FYI, "F_SHLCK\n"); 14268c2ecf20Sopenharmony_ci *type |= server->vals->shared_lock_type; 14278c2ecf20Sopenharmony_ci *lock = 1; 14288c2ecf20Sopenharmony_ci } else 14298c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Unknown type of lock\n"); 14308c2ecf20Sopenharmony_ci} 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_cistatic int 14338c2ecf20Sopenharmony_cicifs_getlk(struct file *file, struct file_lock *flock, __u32 type, 14348c2ecf20Sopenharmony_ci bool wait_flag, bool posix_lck, unsigned int xid) 14358c2ecf20Sopenharmony_ci{ 14368c2ecf20Sopenharmony_ci int rc = 0; 14378c2ecf20Sopenharmony_ci __u64 length = 1 + flock->fl_end - flock->fl_start; 14388c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; 14398c2ecf20Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 14408c2ecf20Sopenharmony_ci struct TCP_Server_Info *server = tcon->ses->server; 14418c2ecf20Sopenharmony_ci __u16 netfid = cfile->fid.netfid; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if (posix_lck) { 14448c2ecf20Sopenharmony_ci int posix_lock_type; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci rc = cifs_posix_lock_test(file, flock); 14478c2ecf20Sopenharmony_ci if (!rc) 14488c2ecf20Sopenharmony_ci return rc; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (type & server->vals->shared_lock_type) 14518c2ecf20Sopenharmony_ci posix_lock_type = CIFS_RDLCK; 14528c2ecf20Sopenharmony_ci else 14538c2ecf20Sopenharmony_ci posix_lock_type = CIFS_WRLCK; 14548c2ecf20Sopenharmony_ci rc = CIFSSMBPosixLock(xid, tcon, netfid, 14558c2ecf20Sopenharmony_ci hash_lockowner(flock->fl_owner), 14568c2ecf20Sopenharmony_ci flock->fl_start, length, flock, 14578c2ecf20Sopenharmony_ci posix_lock_type, wait_flag); 14588c2ecf20Sopenharmony_ci return rc; 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci rc = cifs_lock_test(cfile, flock->fl_start, length, type, flock); 14628c2ecf20Sopenharmony_ci if (!rc) 14638c2ecf20Sopenharmony_ci return rc; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci /* BB we could chain these into one lock request BB */ 14668c2ecf20Sopenharmony_ci rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, type, 14678c2ecf20Sopenharmony_ci 1, 0, false); 14688c2ecf20Sopenharmony_ci if (rc == 0) { 14698c2ecf20Sopenharmony_ci rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, 14708c2ecf20Sopenharmony_ci type, 0, 1, false); 14718c2ecf20Sopenharmony_ci flock->fl_type = F_UNLCK; 14728c2ecf20Sopenharmony_ci if (rc != 0) 14738c2ecf20Sopenharmony_ci cifs_dbg(VFS, "Error unlocking previously locked range %d during test of lock\n", 14748c2ecf20Sopenharmony_ci rc); 14758c2ecf20Sopenharmony_ci return 0; 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (type & server->vals->shared_lock_type) { 14798c2ecf20Sopenharmony_ci flock->fl_type = F_WRLCK; 14808c2ecf20Sopenharmony_ci return 0; 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci type &= ~server->vals->exclusive_lock_type; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, 14868c2ecf20Sopenharmony_ci type | server->vals->shared_lock_type, 14878c2ecf20Sopenharmony_ci 1, 0, false); 14888c2ecf20Sopenharmony_ci if (rc == 0) { 14898c2ecf20Sopenharmony_ci rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, 14908c2ecf20Sopenharmony_ci type | server->vals->shared_lock_type, 0, 1, false); 14918c2ecf20Sopenharmony_ci flock->fl_type = F_RDLCK; 14928c2ecf20Sopenharmony_ci if (rc != 0) 14938c2ecf20Sopenharmony_ci cifs_dbg(VFS, "Error unlocking previously locked range %d during test of lock\n", 14948c2ecf20Sopenharmony_ci rc); 14958c2ecf20Sopenharmony_ci } else 14968c2ecf20Sopenharmony_ci flock->fl_type = F_WRLCK; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci return 0; 14998c2ecf20Sopenharmony_ci} 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_civoid 15028c2ecf20Sopenharmony_cicifs_move_llist(struct list_head *source, struct list_head *dest) 15038c2ecf20Sopenharmony_ci{ 15048c2ecf20Sopenharmony_ci struct list_head *li, *tmp; 15058c2ecf20Sopenharmony_ci list_for_each_safe(li, tmp, source) 15068c2ecf20Sopenharmony_ci list_move(li, dest); 15078c2ecf20Sopenharmony_ci} 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_civoid 15108c2ecf20Sopenharmony_cicifs_free_llist(struct list_head *llist) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci struct cifsLockInfo *li, *tmp; 15138c2ecf20Sopenharmony_ci list_for_each_entry_safe(li, tmp, llist, llist) { 15148c2ecf20Sopenharmony_ci cifs_del_lock_waiters(li); 15158c2ecf20Sopenharmony_ci list_del(&li->llist); 15168c2ecf20Sopenharmony_ci kfree(li); 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ciint 15218c2ecf20Sopenharmony_cicifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock, 15228c2ecf20Sopenharmony_ci unsigned int xid) 15238c2ecf20Sopenharmony_ci{ 15248c2ecf20Sopenharmony_ci int rc = 0, stored_rc; 15258c2ecf20Sopenharmony_ci static const int types[] = { 15268c2ecf20Sopenharmony_ci LOCKING_ANDX_LARGE_FILES, 15278c2ecf20Sopenharmony_ci LOCKING_ANDX_SHARED_LOCK | LOCKING_ANDX_LARGE_FILES 15288c2ecf20Sopenharmony_ci }; 15298c2ecf20Sopenharmony_ci unsigned int i; 15308c2ecf20Sopenharmony_ci unsigned int max_num, num, max_buf; 15318c2ecf20Sopenharmony_ci LOCKING_ANDX_RANGE *buf, *cur; 15328c2ecf20Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 15338c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); 15348c2ecf20Sopenharmony_ci struct cifsLockInfo *li, *tmp; 15358c2ecf20Sopenharmony_ci __u64 length = 1 + flock->fl_end - flock->fl_start; 15368c2ecf20Sopenharmony_ci struct list_head tmp_llist; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tmp_llist); 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci /* 15418c2ecf20Sopenharmony_ci * Accessing maxBuf is racy with cifs_reconnect - need to store value 15428c2ecf20Sopenharmony_ci * and check it before using. 15438c2ecf20Sopenharmony_ci */ 15448c2ecf20Sopenharmony_ci max_buf = tcon->ses->server->maxBuf; 15458c2ecf20Sopenharmony_ci if (max_buf < (sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE))) 15468c2ecf20Sopenharmony_ci return -EINVAL; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct smb_hdr) + sizeof(LOCKING_ANDX_RANGE) > 15498c2ecf20Sopenharmony_ci PAGE_SIZE); 15508c2ecf20Sopenharmony_ci max_buf = min_t(unsigned int, max_buf - sizeof(struct smb_hdr), 15518c2ecf20Sopenharmony_ci PAGE_SIZE); 15528c2ecf20Sopenharmony_ci max_num = (max_buf - sizeof(struct smb_hdr)) / 15538c2ecf20Sopenharmony_ci sizeof(LOCKING_ANDX_RANGE); 15548c2ecf20Sopenharmony_ci buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL); 15558c2ecf20Sopenharmony_ci if (!buf) 15568c2ecf20Sopenharmony_ci return -ENOMEM; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci cifs_down_write(&cinode->lock_sem); 15598c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 15608c2ecf20Sopenharmony_ci cur = buf; 15618c2ecf20Sopenharmony_ci num = 0; 15628c2ecf20Sopenharmony_ci list_for_each_entry_safe(li, tmp, &cfile->llist->locks, llist) { 15638c2ecf20Sopenharmony_ci if (flock->fl_start > li->offset || 15648c2ecf20Sopenharmony_ci (flock->fl_start + length) < 15658c2ecf20Sopenharmony_ci (li->offset + li->length)) 15668c2ecf20Sopenharmony_ci continue; 15678c2ecf20Sopenharmony_ci if (current->tgid != li->pid) 15688c2ecf20Sopenharmony_ci continue; 15698c2ecf20Sopenharmony_ci if (types[i] != li->type) 15708c2ecf20Sopenharmony_ci continue; 15718c2ecf20Sopenharmony_ci if (cinode->can_cache_brlcks) { 15728c2ecf20Sopenharmony_ci /* 15738c2ecf20Sopenharmony_ci * We can cache brlock requests - simply remove 15748c2ecf20Sopenharmony_ci * a lock from the file's list. 15758c2ecf20Sopenharmony_ci */ 15768c2ecf20Sopenharmony_ci list_del(&li->llist); 15778c2ecf20Sopenharmony_ci cifs_del_lock_waiters(li); 15788c2ecf20Sopenharmony_ci kfree(li); 15798c2ecf20Sopenharmony_ci continue; 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci cur->Pid = cpu_to_le16(li->pid); 15828c2ecf20Sopenharmony_ci cur->LengthLow = cpu_to_le32((u32)li->length); 15838c2ecf20Sopenharmony_ci cur->LengthHigh = cpu_to_le32((u32)(li->length>>32)); 15848c2ecf20Sopenharmony_ci cur->OffsetLow = cpu_to_le32((u32)li->offset); 15858c2ecf20Sopenharmony_ci cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32)); 15868c2ecf20Sopenharmony_ci /* 15878c2ecf20Sopenharmony_ci * We need to save a lock here to let us add it again to 15888c2ecf20Sopenharmony_ci * the file's list if the unlock range request fails on 15898c2ecf20Sopenharmony_ci * the server. 15908c2ecf20Sopenharmony_ci */ 15918c2ecf20Sopenharmony_ci list_move(&li->llist, &tmp_llist); 15928c2ecf20Sopenharmony_ci if (++num == max_num) { 15938c2ecf20Sopenharmony_ci stored_rc = cifs_lockv(xid, tcon, 15948c2ecf20Sopenharmony_ci cfile->fid.netfid, 15958c2ecf20Sopenharmony_ci li->type, num, 0, buf); 15968c2ecf20Sopenharmony_ci if (stored_rc) { 15978c2ecf20Sopenharmony_ci /* 15988c2ecf20Sopenharmony_ci * We failed on the unlock range 15998c2ecf20Sopenharmony_ci * request - add all locks from the tmp 16008c2ecf20Sopenharmony_ci * list to the head of the file's list. 16018c2ecf20Sopenharmony_ci */ 16028c2ecf20Sopenharmony_ci cifs_move_llist(&tmp_llist, 16038c2ecf20Sopenharmony_ci &cfile->llist->locks); 16048c2ecf20Sopenharmony_ci rc = stored_rc; 16058c2ecf20Sopenharmony_ci } else 16068c2ecf20Sopenharmony_ci /* 16078c2ecf20Sopenharmony_ci * The unlock range request succeed - 16088c2ecf20Sopenharmony_ci * free the tmp list. 16098c2ecf20Sopenharmony_ci */ 16108c2ecf20Sopenharmony_ci cifs_free_llist(&tmp_llist); 16118c2ecf20Sopenharmony_ci cur = buf; 16128c2ecf20Sopenharmony_ci num = 0; 16138c2ecf20Sopenharmony_ci } else 16148c2ecf20Sopenharmony_ci cur++; 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci if (num) { 16178c2ecf20Sopenharmony_ci stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid, 16188c2ecf20Sopenharmony_ci types[i], num, 0, buf); 16198c2ecf20Sopenharmony_ci if (stored_rc) { 16208c2ecf20Sopenharmony_ci cifs_move_llist(&tmp_llist, 16218c2ecf20Sopenharmony_ci &cfile->llist->locks); 16228c2ecf20Sopenharmony_ci rc = stored_rc; 16238c2ecf20Sopenharmony_ci } else 16248c2ecf20Sopenharmony_ci cifs_free_llist(&tmp_llist); 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci up_write(&cinode->lock_sem); 16298c2ecf20Sopenharmony_ci kfree(buf); 16308c2ecf20Sopenharmony_ci return rc; 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_cistatic int 16348c2ecf20Sopenharmony_cicifs_setlk(struct file *file, struct file_lock *flock, __u32 type, 16358c2ecf20Sopenharmony_ci bool wait_flag, bool posix_lck, int lock, int unlock, 16368c2ecf20Sopenharmony_ci unsigned int xid) 16378c2ecf20Sopenharmony_ci{ 16388c2ecf20Sopenharmony_ci int rc = 0; 16398c2ecf20Sopenharmony_ci __u64 length = 1 + flock->fl_end - flock->fl_start; 16408c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; 16418c2ecf20Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 16428c2ecf20Sopenharmony_ci struct TCP_Server_Info *server = tcon->ses->server; 16438c2ecf20Sopenharmony_ci struct inode *inode = d_inode(cfile->dentry); 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci if (posix_lck) { 16468c2ecf20Sopenharmony_ci int posix_lock_type; 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci rc = cifs_posix_lock_set(file, flock); 16498c2ecf20Sopenharmony_ci if (rc <= FILE_LOCK_DEFERRED) 16508c2ecf20Sopenharmony_ci return rc; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci if (type & server->vals->shared_lock_type) 16538c2ecf20Sopenharmony_ci posix_lock_type = CIFS_RDLCK; 16548c2ecf20Sopenharmony_ci else 16558c2ecf20Sopenharmony_ci posix_lock_type = CIFS_WRLCK; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci if (unlock == 1) 16588c2ecf20Sopenharmony_ci posix_lock_type = CIFS_UNLCK; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci rc = CIFSSMBPosixLock(xid, tcon, cfile->fid.netfid, 16618c2ecf20Sopenharmony_ci hash_lockowner(flock->fl_owner), 16628c2ecf20Sopenharmony_ci flock->fl_start, length, 16638c2ecf20Sopenharmony_ci NULL, posix_lock_type, wait_flag); 16648c2ecf20Sopenharmony_ci goto out; 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci if (lock) { 16688c2ecf20Sopenharmony_ci struct cifsLockInfo *lock; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci lock = cifs_lock_init(flock->fl_start, length, type, 16718c2ecf20Sopenharmony_ci flock->fl_flags); 16728c2ecf20Sopenharmony_ci if (!lock) 16738c2ecf20Sopenharmony_ci return -ENOMEM; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci rc = cifs_lock_add_if(cfile, lock, wait_flag); 16768c2ecf20Sopenharmony_ci if (rc < 0) { 16778c2ecf20Sopenharmony_ci kfree(lock); 16788c2ecf20Sopenharmony_ci return rc; 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_ci if (!rc) 16818c2ecf20Sopenharmony_ci goto out; 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci /* 16848c2ecf20Sopenharmony_ci * Windows 7 server can delay breaking lease from read to None 16858c2ecf20Sopenharmony_ci * if we set a byte-range lock on a file - break it explicitly 16868c2ecf20Sopenharmony_ci * before sending the lock to the server to be sure the next 16878c2ecf20Sopenharmony_ci * read won't conflict with non-overlapted locks due to 16888c2ecf20Sopenharmony_ci * pagereading. 16898c2ecf20Sopenharmony_ci */ 16908c2ecf20Sopenharmony_ci if (!CIFS_CACHE_WRITE(CIFS_I(inode)) && 16918c2ecf20Sopenharmony_ci CIFS_CACHE_READ(CIFS_I(inode))) { 16928c2ecf20Sopenharmony_ci cifs_zap_mapping(inode); 16938c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Set no oplock for inode=%p due to mand locks\n", 16948c2ecf20Sopenharmony_ci inode); 16958c2ecf20Sopenharmony_ci CIFS_I(inode)->oplock = 0; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, 16998c2ecf20Sopenharmony_ci type, 1, 0, wait_flag); 17008c2ecf20Sopenharmony_ci if (rc) { 17018c2ecf20Sopenharmony_ci kfree(lock); 17028c2ecf20Sopenharmony_ci return rc; 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci cifs_lock_add(cfile, lock); 17068c2ecf20Sopenharmony_ci } else if (unlock) 17078c2ecf20Sopenharmony_ci rc = server->ops->mand_unlock_range(cfile, flock, xid); 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ciout: 17108c2ecf20Sopenharmony_ci if ((flock->fl_flags & FL_POSIX) || (flock->fl_flags & FL_FLOCK)) { 17118c2ecf20Sopenharmony_ci /* 17128c2ecf20Sopenharmony_ci * If this is a request to remove all locks because we 17138c2ecf20Sopenharmony_ci * are closing the file, it doesn't matter if the 17148c2ecf20Sopenharmony_ci * unlocking failed as both cifs.ko and the SMB server 17158c2ecf20Sopenharmony_ci * remove the lock on file close 17168c2ecf20Sopenharmony_ci */ 17178c2ecf20Sopenharmony_ci if (rc) { 17188c2ecf20Sopenharmony_ci cifs_dbg(VFS, "%s failed rc=%d\n", __func__, rc); 17198c2ecf20Sopenharmony_ci if (!(flock->fl_flags & FL_CLOSE)) 17208c2ecf20Sopenharmony_ci return rc; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci rc = locks_lock_file_wait(file, flock); 17238c2ecf20Sopenharmony_ci } 17248c2ecf20Sopenharmony_ci return rc; 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ciint cifs_flock(struct file *file, int cmd, struct file_lock *fl) 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci int rc, xid; 17308c2ecf20Sopenharmony_ci int lock = 0, unlock = 0; 17318c2ecf20Sopenharmony_ci bool wait_flag = false; 17328c2ecf20Sopenharmony_ci bool posix_lck = false; 17338c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb; 17348c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 17358c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile; 17368c2ecf20Sopenharmony_ci __u32 type; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci xid = get_xid(); 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci if (!(fl->fl_flags & FL_FLOCK)) { 17418c2ecf20Sopenharmony_ci rc = -ENOLCK; 17428c2ecf20Sopenharmony_ci free_xid(xid); 17438c2ecf20Sopenharmony_ci return rc; 17448c2ecf20Sopenharmony_ci } 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci cfile = (struct cifsFileInfo *)file->private_data; 17478c2ecf20Sopenharmony_ci tcon = tlink_tcon(cfile->tlink); 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci cifs_read_flock(fl, &type, &lock, &unlock, &wait_flag, 17508c2ecf20Sopenharmony_ci tcon->ses->server); 17518c2ecf20Sopenharmony_ci cifs_sb = CIFS_FILE_SB(file); 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci if (cap_unix(tcon->ses) && 17548c2ecf20Sopenharmony_ci (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && 17558c2ecf20Sopenharmony_ci ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) 17568c2ecf20Sopenharmony_ci posix_lck = true; 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci if (!lock && !unlock) { 17598c2ecf20Sopenharmony_ci /* 17608c2ecf20Sopenharmony_ci * if no lock or unlock then nothing to do since we do not 17618c2ecf20Sopenharmony_ci * know what it is 17628c2ecf20Sopenharmony_ci */ 17638c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 17648c2ecf20Sopenharmony_ci free_xid(xid); 17658c2ecf20Sopenharmony_ci return rc; 17668c2ecf20Sopenharmony_ci } 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci rc = cifs_setlk(file, fl, type, wait_flag, posix_lck, lock, unlock, 17698c2ecf20Sopenharmony_ci xid); 17708c2ecf20Sopenharmony_ci free_xid(xid); 17718c2ecf20Sopenharmony_ci return rc; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci} 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ciint cifs_lock(struct file *file, int cmd, struct file_lock *flock) 17778c2ecf20Sopenharmony_ci{ 17788c2ecf20Sopenharmony_ci int rc, xid; 17798c2ecf20Sopenharmony_ci int lock = 0, unlock = 0; 17808c2ecf20Sopenharmony_ci bool wait_flag = false; 17818c2ecf20Sopenharmony_ci bool posix_lck = false; 17828c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb; 17838c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 17848c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile; 17858c2ecf20Sopenharmony_ci __u32 type; 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci rc = -EACCES; 17888c2ecf20Sopenharmony_ci xid = get_xid(); 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld end: %lld\n", 17918c2ecf20Sopenharmony_ci cmd, flock->fl_flags, flock->fl_type, 17928c2ecf20Sopenharmony_ci flock->fl_start, flock->fl_end); 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci cfile = (struct cifsFileInfo *)file->private_data; 17958c2ecf20Sopenharmony_ci tcon = tlink_tcon(cfile->tlink); 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag, 17988c2ecf20Sopenharmony_ci tcon->ses->server); 17998c2ecf20Sopenharmony_ci cifs_sb = CIFS_FILE_SB(file); 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci if (cap_unix(tcon->ses) && 18028c2ecf20Sopenharmony_ci (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && 18038c2ecf20Sopenharmony_ci ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) 18048c2ecf20Sopenharmony_ci posix_lck = true; 18058c2ecf20Sopenharmony_ci /* 18068c2ecf20Sopenharmony_ci * BB add code here to normalize offset and length to account for 18078c2ecf20Sopenharmony_ci * negative length which we can not accept over the wire. 18088c2ecf20Sopenharmony_ci */ 18098c2ecf20Sopenharmony_ci if (IS_GETLK(cmd)) { 18108c2ecf20Sopenharmony_ci rc = cifs_getlk(file, flock, type, wait_flag, posix_lck, xid); 18118c2ecf20Sopenharmony_ci free_xid(xid); 18128c2ecf20Sopenharmony_ci return rc; 18138c2ecf20Sopenharmony_ci } 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci if (!lock && !unlock) { 18168c2ecf20Sopenharmony_ci /* 18178c2ecf20Sopenharmony_ci * if no lock or unlock then nothing to do since we do not 18188c2ecf20Sopenharmony_ci * know what it is 18198c2ecf20Sopenharmony_ci */ 18208c2ecf20Sopenharmony_ci free_xid(xid); 18218c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci rc = cifs_setlk(file, flock, type, wait_flag, posix_lck, lock, unlock, 18258c2ecf20Sopenharmony_ci xid); 18268c2ecf20Sopenharmony_ci free_xid(xid); 18278c2ecf20Sopenharmony_ci return rc; 18288c2ecf20Sopenharmony_ci} 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci/* 18318c2ecf20Sopenharmony_ci * update the file size (if needed) after a write. Should be called with 18328c2ecf20Sopenharmony_ci * the inode->i_lock held 18338c2ecf20Sopenharmony_ci */ 18348c2ecf20Sopenharmony_civoid 18358c2ecf20Sopenharmony_cicifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, 18368c2ecf20Sopenharmony_ci unsigned int bytes_written) 18378c2ecf20Sopenharmony_ci{ 18388c2ecf20Sopenharmony_ci loff_t end_of_write = offset + bytes_written; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci if (end_of_write > cifsi->server_eof) 18418c2ecf20Sopenharmony_ci cifsi->server_eof = end_of_write; 18428c2ecf20Sopenharmony_ci} 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_cistatic ssize_t 18458c2ecf20Sopenharmony_cicifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data, 18468c2ecf20Sopenharmony_ci size_t write_size, loff_t *offset) 18478c2ecf20Sopenharmony_ci{ 18488c2ecf20Sopenharmony_ci int rc = 0; 18498c2ecf20Sopenharmony_ci unsigned int bytes_written = 0; 18508c2ecf20Sopenharmony_ci unsigned int total_written; 18518c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 18528c2ecf20Sopenharmony_ci struct TCP_Server_Info *server; 18538c2ecf20Sopenharmony_ci unsigned int xid; 18548c2ecf20Sopenharmony_ci struct dentry *dentry = open_file->dentry; 18558c2ecf20Sopenharmony_ci struct cifsInodeInfo *cifsi = CIFS_I(d_inode(dentry)); 18568c2ecf20Sopenharmony_ci struct cifs_io_parms io_parms = {0}; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci cifs_dbg(FYI, "write %zd bytes to offset %lld of %pd\n", 18598c2ecf20Sopenharmony_ci write_size, *offset, dentry); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci tcon = tlink_tcon(open_file->tlink); 18628c2ecf20Sopenharmony_ci server = tcon->ses->server; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci if (!server->ops->sync_write) 18658c2ecf20Sopenharmony_ci return -ENOSYS; 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci xid = get_xid(); 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci for (total_written = 0; write_size > total_written; 18708c2ecf20Sopenharmony_ci total_written += bytes_written) { 18718c2ecf20Sopenharmony_ci rc = -EAGAIN; 18728c2ecf20Sopenharmony_ci while (rc == -EAGAIN) { 18738c2ecf20Sopenharmony_ci struct kvec iov[2]; 18748c2ecf20Sopenharmony_ci unsigned int len; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci if (open_file->invalidHandle) { 18778c2ecf20Sopenharmony_ci /* we could deadlock if we called 18788c2ecf20Sopenharmony_ci filemap_fdatawait from here so tell 18798c2ecf20Sopenharmony_ci reopen_file not to flush data to 18808c2ecf20Sopenharmony_ci server now */ 18818c2ecf20Sopenharmony_ci rc = cifs_reopen_file(open_file, false); 18828c2ecf20Sopenharmony_ci if (rc != 0) 18838c2ecf20Sopenharmony_ci break; 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci len = min(server->ops->wp_retry_size(d_inode(dentry)), 18878c2ecf20Sopenharmony_ci (unsigned int)write_size - total_written); 18888c2ecf20Sopenharmony_ci /* iov[0] is reserved for smb header */ 18898c2ecf20Sopenharmony_ci iov[1].iov_base = (char *)write_data + total_written; 18908c2ecf20Sopenharmony_ci iov[1].iov_len = len; 18918c2ecf20Sopenharmony_ci io_parms.pid = pid; 18928c2ecf20Sopenharmony_ci io_parms.tcon = tcon; 18938c2ecf20Sopenharmony_ci io_parms.offset = *offset; 18948c2ecf20Sopenharmony_ci io_parms.length = len; 18958c2ecf20Sopenharmony_ci rc = server->ops->sync_write(xid, &open_file->fid, 18968c2ecf20Sopenharmony_ci &io_parms, &bytes_written, iov, 1); 18978c2ecf20Sopenharmony_ci } 18988c2ecf20Sopenharmony_ci if (rc || (bytes_written == 0)) { 18998c2ecf20Sopenharmony_ci if (total_written) 19008c2ecf20Sopenharmony_ci break; 19018c2ecf20Sopenharmony_ci else { 19028c2ecf20Sopenharmony_ci free_xid(xid); 19038c2ecf20Sopenharmony_ci return rc; 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci } else { 19068c2ecf20Sopenharmony_ci spin_lock(&d_inode(dentry)->i_lock); 19078c2ecf20Sopenharmony_ci cifs_update_eof(cifsi, *offset, bytes_written); 19088c2ecf20Sopenharmony_ci spin_unlock(&d_inode(dentry)->i_lock); 19098c2ecf20Sopenharmony_ci *offset += bytes_written; 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci } 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci cifs_stats_bytes_written(tcon, total_written); 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci if (total_written > 0) { 19168c2ecf20Sopenharmony_ci spin_lock(&d_inode(dentry)->i_lock); 19178c2ecf20Sopenharmony_ci if (*offset > d_inode(dentry)->i_size) 19188c2ecf20Sopenharmony_ci i_size_write(d_inode(dentry), *offset); 19198c2ecf20Sopenharmony_ci spin_unlock(&d_inode(dentry)->i_lock); 19208c2ecf20Sopenharmony_ci } 19218c2ecf20Sopenharmony_ci mark_inode_dirty_sync(d_inode(dentry)); 19228c2ecf20Sopenharmony_ci free_xid(xid); 19238c2ecf20Sopenharmony_ci return total_written; 19248c2ecf20Sopenharmony_ci} 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_cistruct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, 19278c2ecf20Sopenharmony_ci bool fsuid_only) 19288c2ecf20Sopenharmony_ci{ 19298c2ecf20Sopenharmony_ci struct cifsFileInfo *open_file = NULL; 19308c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci /* only filter by fsuid on multiuser mounts */ 19338c2ecf20Sopenharmony_ci if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) 19348c2ecf20Sopenharmony_ci fsuid_only = false; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci spin_lock(&cifs_inode->open_file_lock); 19378c2ecf20Sopenharmony_ci /* we could simply get the first_list_entry since write-only entries 19388c2ecf20Sopenharmony_ci are always at the end of the list but since the first entry might 19398c2ecf20Sopenharmony_ci have a close pending, we go through the whole list */ 19408c2ecf20Sopenharmony_ci list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { 19418c2ecf20Sopenharmony_ci if (fsuid_only && !uid_eq(open_file->uid, current_fsuid())) 19428c2ecf20Sopenharmony_ci continue; 19438c2ecf20Sopenharmony_ci if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) { 19448c2ecf20Sopenharmony_ci if (!open_file->invalidHandle) { 19458c2ecf20Sopenharmony_ci /* found a good file */ 19468c2ecf20Sopenharmony_ci /* lock it so it will not be closed on us */ 19478c2ecf20Sopenharmony_ci cifsFileInfo_get(open_file); 19488c2ecf20Sopenharmony_ci spin_unlock(&cifs_inode->open_file_lock); 19498c2ecf20Sopenharmony_ci return open_file; 19508c2ecf20Sopenharmony_ci } /* else might as well continue, and look for 19518c2ecf20Sopenharmony_ci another, or simply have the caller reopen it 19528c2ecf20Sopenharmony_ci again rather than trying to fix this handle */ 19538c2ecf20Sopenharmony_ci } else /* write only file */ 19548c2ecf20Sopenharmony_ci break; /* write only files are last so must be done */ 19558c2ecf20Sopenharmony_ci } 19568c2ecf20Sopenharmony_ci spin_unlock(&cifs_inode->open_file_lock); 19578c2ecf20Sopenharmony_ci return NULL; 19588c2ecf20Sopenharmony_ci} 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci/* Return -EBADF if no handle is found and general rc otherwise */ 19618c2ecf20Sopenharmony_ciint 19628c2ecf20Sopenharmony_cicifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags, 19638c2ecf20Sopenharmony_ci struct cifsFileInfo **ret_file) 19648c2ecf20Sopenharmony_ci{ 19658c2ecf20Sopenharmony_ci struct cifsFileInfo *open_file, *inv_file = NULL; 19668c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb; 19678c2ecf20Sopenharmony_ci bool any_available = false; 19688c2ecf20Sopenharmony_ci int rc = -EBADF; 19698c2ecf20Sopenharmony_ci unsigned int refind = 0; 19708c2ecf20Sopenharmony_ci bool fsuid_only = flags & FIND_WR_FSUID_ONLY; 19718c2ecf20Sopenharmony_ci bool with_delete = flags & FIND_WR_WITH_DELETE; 19728c2ecf20Sopenharmony_ci *ret_file = NULL; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci /* 19758c2ecf20Sopenharmony_ci * Having a null inode here (because mapping->host was set to zero by 19768c2ecf20Sopenharmony_ci * the VFS or MM) should not happen but we had reports of on oops (due 19778c2ecf20Sopenharmony_ci * to it being zero) during stress testcases so we need to check for it 19788c2ecf20Sopenharmony_ci */ 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci if (cifs_inode == NULL) { 19818c2ecf20Sopenharmony_ci cifs_dbg(VFS, "Null inode passed to cifs_writeable_file\n"); 19828c2ecf20Sopenharmony_ci dump_stack(); 19838c2ecf20Sopenharmony_ci return rc; 19848c2ecf20Sopenharmony_ci } 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci /* only filter by fsuid on multiuser mounts */ 19898c2ecf20Sopenharmony_ci if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) 19908c2ecf20Sopenharmony_ci fsuid_only = false; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci spin_lock(&cifs_inode->open_file_lock); 19938c2ecf20Sopenharmony_cirefind_writable: 19948c2ecf20Sopenharmony_ci if (refind > MAX_REOPEN_ATT) { 19958c2ecf20Sopenharmony_ci spin_unlock(&cifs_inode->open_file_lock); 19968c2ecf20Sopenharmony_ci return rc; 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { 19998c2ecf20Sopenharmony_ci if (!any_available && open_file->pid != current->tgid) 20008c2ecf20Sopenharmony_ci continue; 20018c2ecf20Sopenharmony_ci if (fsuid_only && !uid_eq(open_file->uid, current_fsuid())) 20028c2ecf20Sopenharmony_ci continue; 20038c2ecf20Sopenharmony_ci if (with_delete && !(open_file->fid.access & DELETE)) 20048c2ecf20Sopenharmony_ci continue; 20058c2ecf20Sopenharmony_ci if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { 20068c2ecf20Sopenharmony_ci if (!open_file->invalidHandle) { 20078c2ecf20Sopenharmony_ci /* found a good writable file */ 20088c2ecf20Sopenharmony_ci cifsFileInfo_get(open_file); 20098c2ecf20Sopenharmony_ci spin_unlock(&cifs_inode->open_file_lock); 20108c2ecf20Sopenharmony_ci *ret_file = open_file; 20118c2ecf20Sopenharmony_ci return 0; 20128c2ecf20Sopenharmony_ci } else { 20138c2ecf20Sopenharmony_ci if (!inv_file) 20148c2ecf20Sopenharmony_ci inv_file = open_file; 20158c2ecf20Sopenharmony_ci } 20168c2ecf20Sopenharmony_ci } 20178c2ecf20Sopenharmony_ci } 20188c2ecf20Sopenharmony_ci /* couldn't find useable FH with same pid, try any available */ 20198c2ecf20Sopenharmony_ci if (!any_available) { 20208c2ecf20Sopenharmony_ci any_available = true; 20218c2ecf20Sopenharmony_ci goto refind_writable; 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci if (inv_file) { 20258c2ecf20Sopenharmony_ci any_available = false; 20268c2ecf20Sopenharmony_ci cifsFileInfo_get(inv_file); 20278c2ecf20Sopenharmony_ci } 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci spin_unlock(&cifs_inode->open_file_lock); 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci if (inv_file) { 20328c2ecf20Sopenharmony_ci rc = cifs_reopen_file(inv_file, false); 20338c2ecf20Sopenharmony_ci if (!rc) { 20348c2ecf20Sopenharmony_ci *ret_file = inv_file; 20358c2ecf20Sopenharmony_ci return 0; 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci spin_lock(&cifs_inode->open_file_lock); 20398c2ecf20Sopenharmony_ci list_move_tail(&inv_file->flist, &cifs_inode->openFileList); 20408c2ecf20Sopenharmony_ci spin_unlock(&cifs_inode->open_file_lock); 20418c2ecf20Sopenharmony_ci cifsFileInfo_put(inv_file); 20428c2ecf20Sopenharmony_ci ++refind; 20438c2ecf20Sopenharmony_ci inv_file = NULL; 20448c2ecf20Sopenharmony_ci spin_lock(&cifs_inode->open_file_lock); 20458c2ecf20Sopenharmony_ci goto refind_writable; 20468c2ecf20Sopenharmony_ci } 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci return rc; 20498c2ecf20Sopenharmony_ci} 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_cistruct cifsFileInfo * 20528c2ecf20Sopenharmony_cifind_writable_file(struct cifsInodeInfo *cifs_inode, int flags) 20538c2ecf20Sopenharmony_ci{ 20548c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile; 20558c2ecf20Sopenharmony_ci int rc; 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci rc = cifs_get_writable_file(cifs_inode, flags, &cfile); 20588c2ecf20Sopenharmony_ci if (rc) 20598c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Couldn't find writable handle rc=%d\n", rc); 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci return cfile; 20628c2ecf20Sopenharmony_ci} 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ciint 20658c2ecf20Sopenharmony_cicifs_get_writable_path(struct cifs_tcon *tcon, const char *name, 20668c2ecf20Sopenharmony_ci int flags, 20678c2ecf20Sopenharmony_ci struct cifsFileInfo **ret_file) 20688c2ecf20Sopenharmony_ci{ 20698c2ecf20Sopenharmony_ci struct list_head *tmp; 20708c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile; 20718c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode; 20728c2ecf20Sopenharmony_ci char *full_path; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci *ret_file = NULL; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci spin_lock(&tcon->open_file_lock); 20778c2ecf20Sopenharmony_ci list_for_each(tmp, &tcon->openFileList) { 20788c2ecf20Sopenharmony_ci cfile = list_entry(tmp, struct cifsFileInfo, 20798c2ecf20Sopenharmony_ci tlist); 20808c2ecf20Sopenharmony_ci full_path = build_path_from_dentry(cfile->dentry); 20818c2ecf20Sopenharmony_ci if (full_path == NULL) { 20828c2ecf20Sopenharmony_ci spin_unlock(&tcon->open_file_lock); 20838c2ecf20Sopenharmony_ci return -ENOMEM; 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci if (strcmp(full_path, name)) { 20868c2ecf20Sopenharmony_ci kfree(full_path); 20878c2ecf20Sopenharmony_ci continue; 20888c2ecf20Sopenharmony_ci } 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci kfree(full_path); 20918c2ecf20Sopenharmony_ci cinode = CIFS_I(d_inode(cfile->dentry)); 20928c2ecf20Sopenharmony_ci spin_unlock(&tcon->open_file_lock); 20938c2ecf20Sopenharmony_ci return cifs_get_writable_file(cinode, flags, ret_file); 20948c2ecf20Sopenharmony_ci } 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci spin_unlock(&tcon->open_file_lock); 20978c2ecf20Sopenharmony_ci return -ENOENT; 20988c2ecf20Sopenharmony_ci} 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ciint 21018c2ecf20Sopenharmony_cicifs_get_readable_path(struct cifs_tcon *tcon, const char *name, 21028c2ecf20Sopenharmony_ci struct cifsFileInfo **ret_file) 21038c2ecf20Sopenharmony_ci{ 21048c2ecf20Sopenharmony_ci struct list_head *tmp; 21058c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile; 21068c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode; 21078c2ecf20Sopenharmony_ci char *full_path; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci *ret_file = NULL; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci spin_lock(&tcon->open_file_lock); 21128c2ecf20Sopenharmony_ci list_for_each(tmp, &tcon->openFileList) { 21138c2ecf20Sopenharmony_ci cfile = list_entry(tmp, struct cifsFileInfo, 21148c2ecf20Sopenharmony_ci tlist); 21158c2ecf20Sopenharmony_ci full_path = build_path_from_dentry(cfile->dentry); 21168c2ecf20Sopenharmony_ci if (full_path == NULL) { 21178c2ecf20Sopenharmony_ci spin_unlock(&tcon->open_file_lock); 21188c2ecf20Sopenharmony_ci return -ENOMEM; 21198c2ecf20Sopenharmony_ci } 21208c2ecf20Sopenharmony_ci if (strcmp(full_path, name)) { 21218c2ecf20Sopenharmony_ci kfree(full_path); 21228c2ecf20Sopenharmony_ci continue; 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci kfree(full_path); 21268c2ecf20Sopenharmony_ci cinode = CIFS_I(d_inode(cfile->dentry)); 21278c2ecf20Sopenharmony_ci spin_unlock(&tcon->open_file_lock); 21288c2ecf20Sopenharmony_ci *ret_file = find_readable_file(cinode, 0); 21298c2ecf20Sopenharmony_ci return *ret_file ? 0 : -ENOENT; 21308c2ecf20Sopenharmony_ci } 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci spin_unlock(&tcon->open_file_lock); 21338c2ecf20Sopenharmony_ci return -ENOENT; 21348c2ecf20Sopenharmony_ci} 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_cistatic int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) 21378c2ecf20Sopenharmony_ci{ 21388c2ecf20Sopenharmony_ci struct address_space *mapping = page->mapping; 21398c2ecf20Sopenharmony_ci loff_t offset = (loff_t)page->index << PAGE_SHIFT; 21408c2ecf20Sopenharmony_ci char *write_data; 21418c2ecf20Sopenharmony_ci int rc = -EFAULT; 21428c2ecf20Sopenharmony_ci int bytes_written = 0; 21438c2ecf20Sopenharmony_ci struct inode *inode; 21448c2ecf20Sopenharmony_ci struct cifsFileInfo *open_file; 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci if (!mapping || !mapping->host) 21478c2ecf20Sopenharmony_ci return -EFAULT; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci inode = page->mapping->host; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci offset += (loff_t)from; 21528c2ecf20Sopenharmony_ci write_data = kmap(page); 21538c2ecf20Sopenharmony_ci write_data += from; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci if ((to > PAGE_SIZE) || (from > to)) { 21568c2ecf20Sopenharmony_ci kunmap(page); 21578c2ecf20Sopenharmony_ci return -EIO; 21588c2ecf20Sopenharmony_ci } 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci /* racing with truncate? */ 21618c2ecf20Sopenharmony_ci if (offset > mapping->host->i_size) { 21628c2ecf20Sopenharmony_ci kunmap(page); 21638c2ecf20Sopenharmony_ci return 0; /* don't care */ 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci /* check to make sure that we are not extending the file */ 21678c2ecf20Sopenharmony_ci if (mapping->host->i_size - offset < (loff_t)to) 21688c2ecf20Sopenharmony_ci to = (unsigned)(mapping->host->i_size - offset); 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci rc = cifs_get_writable_file(CIFS_I(mapping->host), FIND_WR_ANY, 21718c2ecf20Sopenharmony_ci &open_file); 21728c2ecf20Sopenharmony_ci if (!rc) { 21738c2ecf20Sopenharmony_ci bytes_written = cifs_write(open_file, open_file->pid, 21748c2ecf20Sopenharmony_ci write_data, to - from, &offset); 21758c2ecf20Sopenharmony_ci cifsFileInfo_put(open_file); 21768c2ecf20Sopenharmony_ci /* Does mm or vfs already set times? */ 21778c2ecf20Sopenharmony_ci inode->i_atime = inode->i_mtime = current_time(inode); 21788c2ecf20Sopenharmony_ci if ((bytes_written > 0) && (offset)) 21798c2ecf20Sopenharmony_ci rc = 0; 21808c2ecf20Sopenharmony_ci else if (bytes_written < 0) 21818c2ecf20Sopenharmony_ci rc = bytes_written; 21828c2ecf20Sopenharmony_ci else 21838c2ecf20Sopenharmony_ci rc = -EFAULT; 21848c2ecf20Sopenharmony_ci } else { 21858c2ecf20Sopenharmony_ci cifs_dbg(FYI, "No writable handle for write page rc=%d\n", rc); 21868c2ecf20Sopenharmony_ci if (!is_retryable_error(rc)) 21878c2ecf20Sopenharmony_ci rc = -EIO; 21888c2ecf20Sopenharmony_ci } 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci kunmap(page); 21918c2ecf20Sopenharmony_ci return rc; 21928c2ecf20Sopenharmony_ci} 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_cistatic struct cifs_writedata * 21958c2ecf20Sopenharmony_ciwdata_alloc_and_fillpages(pgoff_t tofind, struct address_space *mapping, 21968c2ecf20Sopenharmony_ci pgoff_t end, pgoff_t *index, 21978c2ecf20Sopenharmony_ci unsigned int *found_pages) 21988c2ecf20Sopenharmony_ci{ 21998c2ecf20Sopenharmony_ci struct cifs_writedata *wdata; 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci wdata = cifs_writedata_alloc((unsigned int)tofind, 22028c2ecf20Sopenharmony_ci cifs_writev_complete); 22038c2ecf20Sopenharmony_ci if (!wdata) 22048c2ecf20Sopenharmony_ci return NULL; 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci *found_pages = find_get_pages_range_tag(mapping, index, end, 22078c2ecf20Sopenharmony_ci PAGECACHE_TAG_DIRTY, tofind, wdata->pages); 22088c2ecf20Sopenharmony_ci return wdata; 22098c2ecf20Sopenharmony_ci} 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_cistatic unsigned int 22128c2ecf20Sopenharmony_ciwdata_prepare_pages(struct cifs_writedata *wdata, unsigned int found_pages, 22138c2ecf20Sopenharmony_ci struct address_space *mapping, 22148c2ecf20Sopenharmony_ci struct writeback_control *wbc, 22158c2ecf20Sopenharmony_ci pgoff_t end, pgoff_t *index, pgoff_t *next, bool *done) 22168c2ecf20Sopenharmony_ci{ 22178c2ecf20Sopenharmony_ci unsigned int nr_pages = 0, i; 22188c2ecf20Sopenharmony_ci struct page *page; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci for (i = 0; i < found_pages; i++) { 22218c2ecf20Sopenharmony_ci page = wdata->pages[i]; 22228c2ecf20Sopenharmony_ci /* 22238c2ecf20Sopenharmony_ci * At this point we hold neither the i_pages lock nor the 22248c2ecf20Sopenharmony_ci * page lock: the page may be truncated or invalidated 22258c2ecf20Sopenharmony_ci * (changing page->mapping to NULL), or even swizzled 22268c2ecf20Sopenharmony_ci * back from swapper_space to tmpfs file mapping 22278c2ecf20Sopenharmony_ci */ 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci if (nr_pages == 0) 22308c2ecf20Sopenharmony_ci lock_page(page); 22318c2ecf20Sopenharmony_ci else if (!trylock_page(page)) 22328c2ecf20Sopenharmony_ci break; 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci if (unlikely(page->mapping != mapping)) { 22358c2ecf20Sopenharmony_ci unlock_page(page); 22368c2ecf20Sopenharmony_ci break; 22378c2ecf20Sopenharmony_ci } 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci if (!wbc->range_cyclic && page->index > end) { 22408c2ecf20Sopenharmony_ci *done = true; 22418c2ecf20Sopenharmony_ci unlock_page(page); 22428c2ecf20Sopenharmony_ci break; 22438c2ecf20Sopenharmony_ci } 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci if (*next && (page->index != *next)) { 22468c2ecf20Sopenharmony_ci /* Not next consecutive page */ 22478c2ecf20Sopenharmony_ci unlock_page(page); 22488c2ecf20Sopenharmony_ci break; 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci if (wbc->sync_mode != WB_SYNC_NONE) 22528c2ecf20Sopenharmony_ci wait_on_page_writeback(page); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci if (PageWriteback(page) || 22558c2ecf20Sopenharmony_ci !clear_page_dirty_for_io(page)) { 22568c2ecf20Sopenharmony_ci unlock_page(page); 22578c2ecf20Sopenharmony_ci break; 22588c2ecf20Sopenharmony_ci } 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci /* 22618c2ecf20Sopenharmony_ci * This actually clears the dirty bit in the radix tree. 22628c2ecf20Sopenharmony_ci * See cifs_writepage() for more commentary. 22638c2ecf20Sopenharmony_ci */ 22648c2ecf20Sopenharmony_ci set_page_writeback(page); 22658c2ecf20Sopenharmony_ci if (page_offset(page) >= i_size_read(mapping->host)) { 22668c2ecf20Sopenharmony_ci *done = true; 22678c2ecf20Sopenharmony_ci unlock_page(page); 22688c2ecf20Sopenharmony_ci end_page_writeback(page); 22698c2ecf20Sopenharmony_ci break; 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci wdata->pages[i] = page; 22738c2ecf20Sopenharmony_ci *next = page->index + 1; 22748c2ecf20Sopenharmony_ci ++nr_pages; 22758c2ecf20Sopenharmony_ci } 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci /* reset index to refind any pages skipped */ 22788c2ecf20Sopenharmony_ci if (nr_pages == 0) 22798c2ecf20Sopenharmony_ci *index = wdata->pages[0]->index + 1; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci /* put any pages we aren't going to use */ 22828c2ecf20Sopenharmony_ci for (i = nr_pages; i < found_pages; i++) { 22838c2ecf20Sopenharmony_ci put_page(wdata->pages[i]); 22848c2ecf20Sopenharmony_ci wdata->pages[i] = NULL; 22858c2ecf20Sopenharmony_ci } 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci return nr_pages; 22888c2ecf20Sopenharmony_ci} 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_cistatic int 22918c2ecf20Sopenharmony_ciwdata_send_pages(struct cifs_writedata *wdata, unsigned int nr_pages, 22928c2ecf20Sopenharmony_ci struct address_space *mapping, struct writeback_control *wbc) 22938c2ecf20Sopenharmony_ci{ 22948c2ecf20Sopenharmony_ci int rc; 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci wdata->sync_mode = wbc->sync_mode; 22978c2ecf20Sopenharmony_ci wdata->nr_pages = nr_pages; 22988c2ecf20Sopenharmony_ci wdata->offset = page_offset(wdata->pages[0]); 22998c2ecf20Sopenharmony_ci wdata->pagesz = PAGE_SIZE; 23008c2ecf20Sopenharmony_ci wdata->tailsz = min(i_size_read(mapping->host) - 23018c2ecf20Sopenharmony_ci page_offset(wdata->pages[nr_pages - 1]), 23028c2ecf20Sopenharmony_ci (loff_t)PAGE_SIZE); 23038c2ecf20Sopenharmony_ci wdata->bytes = ((nr_pages - 1) * PAGE_SIZE) + wdata->tailsz; 23048c2ecf20Sopenharmony_ci wdata->pid = wdata->cfile->pid; 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci rc = adjust_credits(wdata->server, &wdata->credits, wdata->bytes); 23078c2ecf20Sopenharmony_ci if (rc) 23088c2ecf20Sopenharmony_ci return rc; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci if (wdata->cfile->invalidHandle) 23118c2ecf20Sopenharmony_ci rc = -EAGAIN; 23128c2ecf20Sopenharmony_ci else 23138c2ecf20Sopenharmony_ci rc = wdata->server->ops->async_writev(wdata, 23148c2ecf20Sopenharmony_ci cifs_writedata_release); 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci return rc; 23178c2ecf20Sopenharmony_ci} 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_cistatic int cifs_writepages(struct address_space *mapping, 23208c2ecf20Sopenharmony_ci struct writeback_control *wbc) 23218c2ecf20Sopenharmony_ci{ 23228c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 23238c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 23248c2ecf20Sopenharmony_ci struct TCP_Server_Info *server; 23258c2ecf20Sopenharmony_ci bool done = false, scanned = false, range_whole = false; 23268c2ecf20Sopenharmony_ci pgoff_t end, index; 23278c2ecf20Sopenharmony_ci struct cifs_writedata *wdata; 23288c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile = NULL; 23298c2ecf20Sopenharmony_ci int rc = 0; 23308c2ecf20Sopenharmony_ci int saved_rc = 0; 23318c2ecf20Sopenharmony_ci unsigned int xid; 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci /* 23348c2ecf20Sopenharmony_ci * If wsize is smaller than the page cache size, default to writing 23358c2ecf20Sopenharmony_ci * one page at a time via cifs_writepage 23368c2ecf20Sopenharmony_ci */ 23378c2ecf20Sopenharmony_ci if (cifs_sb->wsize < PAGE_SIZE) 23388c2ecf20Sopenharmony_ci return generic_writepages(mapping, wbc); 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci xid = get_xid(); 23418c2ecf20Sopenharmony_ci if (wbc->range_cyclic) { 23428c2ecf20Sopenharmony_ci index = mapping->writeback_index; /* Start from prev offset */ 23438c2ecf20Sopenharmony_ci end = -1; 23448c2ecf20Sopenharmony_ci } else { 23458c2ecf20Sopenharmony_ci index = wbc->range_start >> PAGE_SHIFT; 23468c2ecf20Sopenharmony_ci end = wbc->range_end >> PAGE_SHIFT; 23478c2ecf20Sopenharmony_ci if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) 23488c2ecf20Sopenharmony_ci range_whole = true; 23498c2ecf20Sopenharmony_ci scanned = true; 23508c2ecf20Sopenharmony_ci } 23518c2ecf20Sopenharmony_ci server = cifs_pick_channel(cifs_sb_master_tcon(cifs_sb)->ses); 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ciretry: 23548c2ecf20Sopenharmony_ci while (!done && index <= end) { 23558c2ecf20Sopenharmony_ci unsigned int i, nr_pages, found_pages, wsize; 23568c2ecf20Sopenharmony_ci pgoff_t next = 0, tofind, saved_index = index; 23578c2ecf20Sopenharmony_ci struct cifs_credits credits_on_stack; 23588c2ecf20Sopenharmony_ci struct cifs_credits *credits = &credits_on_stack; 23598c2ecf20Sopenharmony_ci int get_file_rc = 0; 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci if (cfile) 23628c2ecf20Sopenharmony_ci cifsFileInfo_put(cfile); 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY, &cfile); 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci /* in case of an error store it to return later */ 23678c2ecf20Sopenharmony_ci if (rc) 23688c2ecf20Sopenharmony_ci get_file_rc = rc; 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, 23718c2ecf20Sopenharmony_ci &wsize, credits); 23728c2ecf20Sopenharmony_ci if (rc != 0) { 23738c2ecf20Sopenharmony_ci done = true; 23748c2ecf20Sopenharmony_ci break; 23758c2ecf20Sopenharmony_ci } 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci tofind = min((wsize / PAGE_SIZE) - 1, end - index) + 1; 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci wdata = wdata_alloc_and_fillpages(tofind, mapping, end, &index, 23808c2ecf20Sopenharmony_ci &found_pages); 23818c2ecf20Sopenharmony_ci if (!wdata) { 23828c2ecf20Sopenharmony_ci rc = -ENOMEM; 23838c2ecf20Sopenharmony_ci done = true; 23848c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 23858c2ecf20Sopenharmony_ci break; 23868c2ecf20Sopenharmony_ci } 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci if (found_pages == 0) { 23898c2ecf20Sopenharmony_ci kref_put(&wdata->refcount, cifs_writedata_release); 23908c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 23918c2ecf20Sopenharmony_ci break; 23928c2ecf20Sopenharmony_ci } 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci nr_pages = wdata_prepare_pages(wdata, found_pages, mapping, wbc, 23958c2ecf20Sopenharmony_ci end, &index, &next, &done); 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci /* nothing to write? */ 23988c2ecf20Sopenharmony_ci if (nr_pages == 0) { 23998c2ecf20Sopenharmony_ci kref_put(&wdata->refcount, cifs_writedata_release); 24008c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 24018c2ecf20Sopenharmony_ci continue; 24028c2ecf20Sopenharmony_ci } 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci wdata->credits = credits_on_stack; 24058c2ecf20Sopenharmony_ci wdata->cfile = cfile; 24068c2ecf20Sopenharmony_ci wdata->server = server; 24078c2ecf20Sopenharmony_ci cfile = NULL; 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci if (!wdata->cfile) { 24108c2ecf20Sopenharmony_ci cifs_dbg(VFS, "No writable handle in writepages rc=%d\n", 24118c2ecf20Sopenharmony_ci get_file_rc); 24128c2ecf20Sopenharmony_ci if (is_retryable_error(get_file_rc)) 24138c2ecf20Sopenharmony_ci rc = get_file_rc; 24148c2ecf20Sopenharmony_ci else 24158c2ecf20Sopenharmony_ci rc = -EBADF; 24168c2ecf20Sopenharmony_ci } else 24178c2ecf20Sopenharmony_ci rc = wdata_send_pages(wdata, nr_pages, mapping, wbc); 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci for (i = 0; i < nr_pages; ++i) 24208c2ecf20Sopenharmony_ci unlock_page(wdata->pages[i]); 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci /* send failure -- clean up the mess */ 24238c2ecf20Sopenharmony_ci if (rc != 0) { 24248c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, &wdata->credits, 0); 24258c2ecf20Sopenharmony_ci for (i = 0; i < nr_pages; ++i) { 24268c2ecf20Sopenharmony_ci if (is_retryable_error(rc)) 24278c2ecf20Sopenharmony_ci redirty_page_for_writepage(wbc, 24288c2ecf20Sopenharmony_ci wdata->pages[i]); 24298c2ecf20Sopenharmony_ci else 24308c2ecf20Sopenharmony_ci SetPageError(wdata->pages[i]); 24318c2ecf20Sopenharmony_ci end_page_writeback(wdata->pages[i]); 24328c2ecf20Sopenharmony_ci put_page(wdata->pages[i]); 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci if (!is_retryable_error(rc)) 24358c2ecf20Sopenharmony_ci mapping_set_error(mapping, rc); 24368c2ecf20Sopenharmony_ci } 24378c2ecf20Sopenharmony_ci kref_put(&wdata->refcount, cifs_writedata_release); 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN) { 24408c2ecf20Sopenharmony_ci index = saved_index; 24418c2ecf20Sopenharmony_ci continue; 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci /* Return immediately if we received a signal during writing */ 24458c2ecf20Sopenharmony_ci if (is_interrupt_error(rc)) { 24468c2ecf20Sopenharmony_ci done = true; 24478c2ecf20Sopenharmony_ci break; 24488c2ecf20Sopenharmony_ci } 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci if (rc != 0 && saved_rc == 0) 24518c2ecf20Sopenharmony_ci saved_rc = rc; 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci wbc->nr_to_write -= nr_pages; 24548c2ecf20Sopenharmony_ci if (wbc->nr_to_write <= 0) 24558c2ecf20Sopenharmony_ci done = true; 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci index = next; 24588c2ecf20Sopenharmony_ci } 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci if (!scanned && !done) { 24618c2ecf20Sopenharmony_ci /* 24628c2ecf20Sopenharmony_ci * We hit the last page and there is more work to be done: wrap 24638c2ecf20Sopenharmony_ci * back to the start of the file 24648c2ecf20Sopenharmony_ci */ 24658c2ecf20Sopenharmony_ci scanned = true; 24668c2ecf20Sopenharmony_ci index = 0; 24678c2ecf20Sopenharmony_ci goto retry; 24688c2ecf20Sopenharmony_ci } 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci if (saved_rc != 0) 24718c2ecf20Sopenharmony_ci rc = saved_rc; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) 24748c2ecf20Sopenharmony_ci mapping->writeback_index = index; 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci if (cfile) 24778c2ecf20Sopenharmony_ci cifsFileInfo_put(cfile); 24788c2ecf20Sopenharmony_ci free_xid(xid); 24798c2ecf20Sopenharmony_ci return rc; 24808c2ecf20Sopenharmony_ci} 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_cistatic int 24838c2ecf20Sopenharmony_cicifs_writepage_locked(struct page *page, struct writeback_control *wbc) 24848c2ecf20Sopenharmony_ci{ 24858c2ecf20Sopenharmony_ci int rc; 24868c2ecf20Sopenharmony_ci unsigned int xid; 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci xid = get_xid(); 24898c2ecf20Sopenharmony_ci/* BB add check for wbc flags */ 24908c2ecf20Sopenharmony_ci get_page(page); 24918c2ecf20Sopenharmony_ci if (!PageUptodate(page)) 24928c2ecf20Sopenharmony_ci cifs_dbg(FYI, "ppw - page not up to date\n"); 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci /* 24958c2ecf20Sopenharmony_ci * Set the "writeback" flag, and clear "dirty" in the radix tree. 24968c2ecf20Sopenharmony_ci * 24978c2ecf20Sopenharmony_ci * A writepage() implementation always needs to do either this, 24988c2ecf20Sopenharmony_ci * or re-dirty the page with "redirty_page_for_writepage()" in 24998c2ecf20Sopenharmony_ci * the case of a failure. 25008c2ecf20Sopenharmony_ci * 25018c2ecf20Sopenharmony_ci * Just unlocking the page will cause the radix tree tag-bits 25028c2ecf20Sopenharmony_ci * to fail to update with the state of the page correctly. 25038c2ecf20Sopenharmony_ci */ 25048c2ecf20Sopenharmony_ci set_page_writeback(page); 25058c2ecf20Sopenharmony_ciretry_write: 25068c2ecf20Sopenharmony_ci rc = cifs_partialpagewrite(page, 0, PAGE_SIZE); 25078c2ecf20Sopenharmony_ci if (is_retryable_error(rc)) { 25088c2ecf20Sopenharmony_ci if (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN) 25098c2ecf20Sopenharmony_ci goto retry_write; 25108c2ecf20Sopenharmony_ci redirty_page_for_writepage(wbc, page); 25118c2ecf20Sopenharmony_ci } else if (rc != 0) { 25128c2ecf20Sopenharmony_ci SetPageError(page); 25138c2ecf20Sopenharmony_ci mapping_set_error(page->mapping, rc); 25148c2ecf20Sopenharmony_ci } else { 25158c2ecf20Sopenharmony_ci SetPageUptodate(page); 25168c2ecf20Sopenharmony_ci } 25178c2ecf20Sopenharmony_ci end_page_writeback(page); 25188c2ecf20Sopenharmony_ci put_page(page); 25198c2ecf20Sopenharmony_ci free_xid(xid); 25208c2ecf20Sopenharmony_ci return rc; 25218c2ecf20Sopenharmony_ci} 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_cistatic int cifs_writepage(struct page *page, struct writeback_control *wbc) 25248c2ecf20Sopenharmony_ci{ 25258c2ecf20Sopenharmony_ci int rc = cifs_writepage_locked(page, wbc); 25268c2ecf20Sopenharmony_ci unlock_page(page); 25278c2ecf20Sopenharmony_ci return rc; 25288c2ecf20Sopenharmony_ci} 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_cistatic int cifs_write_end(struct file *file, struct address_space *mapping, 25318c2ecf20Sopenharmony_ci loff_t pos, unsigned len, unsigned copied, 25328c2ecf20Sopenharmony_ci struct page *page, void *fsdata) 25338c2ecf20Sopenharmony_ci{ 25348c2ecf20Sopenharmony_ci int rc; 25358c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 25368c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile = file->private_data; 25378c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb); 25388c2ecf20Sopenharmony_ci __u32 pid; 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) 25418c2ecf20Sopenharmony_ci pid = cfile->pid; 25428c2ecf20Sopenharmony_ci else 25438c2ecf20Sopenharmony_ci pid = current->tgid; 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_ci cifs_dbg(FYI, "write_end for page %p from pos %lld with %d bytes\n", 25468c2ecf20Sopenharmony_ci page, pos, copied); 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci if (PageChecked(page)) { 25498c2ecf20Sopenharmony_ci if (copied == len) 25508c2ecf20Sopenharmony_ci SetPageUptodate(page); 25518c2ecf20Sopenharmony_ci ClearPageChecked(page); 25528c2ecf20Sopenharmony_ci } else if (!PageUptodate(page) && copied == PAGE_SIZE) 25538c2ecf20Sopenharmony_ci SetPageUptodate(page); 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci if (!PageUptodate(page)) { 25568c2ecf20Sopenharmony_ci char *page_data; 25578c2ecf20Sopenharmony_ci unsigned offset = pos & (PAGE_SIZE - 1); 25588c2ecf20Sopenharmony_ci unsigned int xid; 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci xid = get_xid(); 25618c2ecf20Sopenharmony_ci /* this is probably better than directly calling 25628c2ecf20Sopenharmony_ci partialpage_write since in this function the file handle is 25638c2ecf20Sopenharmony_ci known which we might as well leverage */ 25648c2ecf20Sopenharmony_ci /* BB check if anything else missing out of ppw 25658c2ecf20Sopenharmony_ci such as updating last write time */ 25668c2ecf20Sopenharmony_ci page_data = kmap(page); 25678c2ecf20Sopenharmony_ci rc = cifs_write(cfile, pid, page_data + offset, copied, &pos); 25688c2ecf20Sopenharmony_ci /* if (rc < 0) should we set writebehind rc? */ 25698c2ecf20Sopenharmony_ci kunmap(page); 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci free_xid(xid); 25728c2ecf20Sopenharmony_ci } else { 25738c2ecf20Sopenharmony_ci rc = copied; 25748c2ecf20Sopenharmony_ci pos += copied; 25758c2ecf20Sopenharmony_ci set_page_dirty(page); 25768c2ecf20Sopenharmony_ci } 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci if (rc > 0) { 25798c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 25808c2ecf20Sopenharmony_ci if (pos > inode->i_size) 25818c2ecf20Sopenharmony_ci i_size_write(inode, pos); 25828c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 25838c2ecf20Sopenharmony_ci } 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci unlock_page(page); 25868c2ecf20Sopenharmony_ci put_page(page); 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci return rc; 25898c2ecf20Sopenharmony_ci} 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ciint cifs_strict_fsync(struct file *file, loff_t start, loff_t end, 25928c2ecf20Sopenharmony_ci int datasync) 25938c2ecf20Sopenharmony_ci{ 25948c2ecf20Sopenharmony_ci unsigned int xid; 25958c2ecf20Sopenharmony_ci int rc = 0; 25968c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 25978c2ecf20Sopenharmony_ci struct TCP_Server_Info *server; 25988c2ecf20Sopenharmony_ci struct cifsFileInfo *smbfile = file->private_data; 25998c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 26008c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci rc = file_write_and_wait_range(file, start, end); 26038c2ecf20Sopenharmony_ci if (rc) { 26048c2ecf20Sopenharmony_ci trace_cifs_fsync_err(inode->i_ino, rc); 26058c2ecf20Sopenharmony_ci return rc; 26068c2ecf20Sopenharmony_ci } 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci xid = get_xid(); 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Sync file - name: %pD datasync: 0x%x\n", 26118c2ecf20Sopenharmony_ci file, datasync); 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci if (!CIFS_CACHE_READ(CIFS_I(inode))) { 26148c2ecf20Sopenharmony_ci rc = cifs_zap_mapping(inode); 26158c2ecf20Sopenharmony_ci if (rc) { 26168c2ecf20Sopenharmony_ci cifs_dbg(FYI, "rc: %d during invalidate phase\n", rc); 26178c2ecf20Sopenharmony_ci rc = 0; /* don't care about it in fsync */ 26188c2ecf20Sopenharmony_ci } 26198c2ecf20Sopenharmony_ci } 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci tcon = tlink_tcon(smbfile->tlink); 26228c2ecf20Sopenharmony_ci if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) { 26238c2ecf20Sopenharmony_ci server = tcon->ses->server; 26248c2ecf20Sopenharmony_ci if (server->ops->flush == NULL) { 26258c2ecf20Sopenharmony_ci rc = -ENOSYS; 26268c2ecf20Sopenharmony_ci goto strict_fsync_exit; 26278c2ecf20Sopenharmony_ci } 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) { 26308c2ecf20Sopenharmony_ci smbfile = find_writable_file(CIFS_I(inode), FIND_WR_ANY); 26318c2ecf20Sopenharmony_ci if (smbfile) { 26328c2ecf20Sopenharmony_ci rc = server->ops->flush(xid, tcon, &smbfile->fid); 26338c2ecf20Sopenharmony_ci cifsFileInfo_put(smbfile); 26348c2ecf20Sopenharmony_ci } else 26358c2ecf20Sopenharmony_ci cifs_dbg(FYI, "ignore fsync for file not open for write\n"); 26368c2ecf20Sopenharmony_ci } else 26378c2ecf20Sopenharmony_ci rc = server->ops->flush(xid, tcon, &smbfile->fid); 26388c2ecf20Sopenharmony_ci } 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_cistrict_fsync_exit: 26418c2ecf20Sopenharmony_ci free_xid(xid); 26428c2ecf20Sopenharmony_ci return rc; 26438c2ecf20Sopenharmony_ci} 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ciint cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) 26468c2ecf20Sopenharmony_ci{ 26478c2ecf20Sopenharmony_ci unsigned int xid; 26488c2ecf20Sopenharmony_ci int rc = 0; 26498c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 26508c2ecf20Sopenharmony_ci struct TCP_Server_Info *server; 26518c2ecf20Sopenharmony_ci struct cifsFileInfo *smbfile = file->private_data; 26528c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 26538c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file); 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci rc = file_write_and_wait_range(file, start, end); 26568c2ecf20Sopenharmony_ci if (rc) { 26578c2ecf20Sopenharmony_ci trace_cifs_fsync_err(file_inode(file)->i_ino, rc); 26588c2ecf20Sopenharmony_ci return rc; 26598c2ecf20Sopenharmony_ci } 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci xid = get_xid(); 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Sync file - name: %pD datasync: 0x%x\n", 26648c2ecf20Sopenharmony_ci file, datasync); 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci tcon = tlink_tcon(smbfile->tlink); 26678c2ecf20Sopenharmony_ci if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) { 26688c2ecf20Sopenharmony_ci server = tcon->ses->server; 26698c2ecf20Sopenharmony_ci if (server->ops->flush == NULL) { 26708c2ecf20Sopenharmony_ci rc = -ENOSYS; 26718c2ecf20Sopenharmony_ci goto fsync_exit; 26728c2ecf20Sopenharmony_ci } 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci if ((OPEN_FMODE(smbfile->f_flags) & FMODE_WRITE) == 0) { 26758c2ecf20Sopenharmony_ci smbfile = find_writable_file(CIFS_I(inode), FIND_WR_ANY); 26768c2ecf20Sopenharmony_ci if (smbfile) { 26778c2ecf20Sopenharmony_ci rc = server->ops->flush(xid, tcon, &smbfile->fid); 26788c2ecf20Sopenharmony_ci cifsFileInfo_put(smbfile); 26798c2ecf20Sopenharmony_ci } else 26808c2ecf20Sopenharmony_ci cifs_dbg(FYI, "ignore fsync for file not open for write\n"); 26818c2ecf20Sopenharmony_ci } else 26828c2ecf20Sopenharmony_ci rc = server->ops->flush(xid, tcon, &smbfile->fid); 26838c2ecf20Sopenharmony_ci } 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_cifsync_exit: 26868c2ecf20Sopenharmony_ci free_xid(xid); 26878c2ecf20Sopenharmony_ci return rc; 26888c2ecf20Sopenharmony_ci} 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci/* 26918c2ecf20Sopenharmony_ci * As file closes, flush all cached write data for this inode checking 26928c2ecf20Sopenharmony_ci * for write behind errors. 26938c2ecf20Sopenharmony_ci */ 26948c2ecf20Sopenharmony_ciint cifs_flush(struct file *file, fl_owner_t id) 26958c2ecf20Sopenharmony_ci{ 26968c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 26978c2ecf20Sopenharmony_ci int rc = 0; 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci if (file->f_mode & FMODE_WRITE) 27008c2ecf20Sopenharmony_ci rc = filemap_write_and_wait(inode->i_mapping); 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Flush inode %p file %p rc %d\n", inode, file, rc); 27038c2ecf20Sopenharmony_ci if (rc) 27048c2ecf20Sopenharmony_ci trace_cifs_flush_err(inode->i_ino, rc); 27058c2ecf20Sopenharmony_ci return rc; 27068c2ecf20Sopenharmony_ci} 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_cistatic int 27098c2ecf20Sopenharmony_cicifs_write_allocate_pages(struct page **pages, unsigned long num_pages) 27108c2ecf20Sopenharmony_ci{ 27118c2ecf20Sopenharmony_ci int rc = 0; 27128c2ecf20Sopenharmony_ci unsigned long i; 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci for (i = 0; i < num_pages; i++) { 27158c2ecf20Sopenharmony_ci pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); 27168c2ecf20Sopenharmony_ci if (!pages[i]) { 27178c2ecf20Sopenharmony_ci /* 27188c2ecf20Sopenharmony_ci * save number of pages we have already allocated and 27198c2ecf20Sopenharmony_ci * return with ENOMEM error 27208c2ecf20Sopenharmony_ci */ 27218c2ecf20Sopenharmony_ci num_pages = i; 27228c2ecf20Sopenharmony_ci rc = -ENOMEM; 27238c2ecf20Sopenharmony_ci break; 27248c2ecf20Sopenharmony_ci } 27258c2ecf20Sopenharmony_ci } 27268c2ecf20Sopenharmony_ci 27278c2ecf20Sopenharmony_ci if (rc) { 27288c2ecf20Sopenharmony_ci for (i = 0; i < num_pages; i++) 27298c2ecf20Sopenharmony_ci put_page(pages[i]); 27308c2ecf20Sopenharmony_ci } 27318c2ecf20Sopenharmony_ci return rc; 27328c2ecf20Sopenharmony_ci} 27338c2ecf20Sopenharmony_ci 27348c2ecf20Sopenharmony_cistatic inline 27358c2ecf20Sopenharmony_cisize_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len) 27368c2ecf20Sopenharmony_ci{ 27378c2ecf20Sopenharmony_ci size_t num_pages; 27388c2ecf20Sopenharmony_ci size_t clen; 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci clen = min_t(const size_t, len, wsize); 27418c2ecf20Sopenharmony_ci num_pages = DIV_ROUND_UP(clen, PAGE_SIZE); 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci if (cur_len) 27448c2ecf20Sopenharmony_ci *cur_len = clen; 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci return num_pages; 27478c2ecf20Sopenharmony_ci} 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_cistatic void 27508c2ecf20Sopenharmony_cicifs_uncached_writedata_release(struct kref *refcount) 27518c2ecf20Sopenharmony_ci{ 27528c2ecf20Sopenharmony_ci int i; 27538c2ecf20Sopenharmony_ci struct cifs_writedata *wdata = container_of(refcount, 27548c2ecf20Sopenharmony_ci struct cifs_writedata, refcount); 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci kref_put(&wdata->ctx->refcount, cifs_aio_ctx_release); 27578c2ecf20Sopenharmony_ci for (i = 0; i < wdata->nr_pages; i++) 27588c2ecf20Sopenharmony_ci put_page(wdata->pages[i]); 27598c2ecf20Sopenharmony_ci cifs_writedata_release(refcount); 27608c2ecf20Sopenharmony_ci} 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_cistatic void collect_uncached_write_data(struct cifs_aio_ctx *ctx); 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_cistatic void 27658c2ecf20Sopenharmony_cicifs_uncached_writev_complete(struct work_struct *work) 27668c2ecf20Sopenharmony_ci{ 27678c2ecf20Sopenharmony_ci struct cifs_writedata *wdata = container_of(work, 27688c2ecf20Sopenharmony_ci struct cifs_writedata, work); 27698c2ecf20Sopenharmony_ci struct inode *inode = d_inode(wdata->cfile->dentry); 27708c2ecf20Sopenharmony_ci struct cifsInodeInfo *cifsi = CIFS_I(inode); 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 27738c2ecf20Sopenharmony_ci cifs_update_eof(cifsi, wdata->offset, wdata->bytes); 27748c2ecf20Sopenharmony_ci if (cifsi->server_eof > inode->i_size) 27758c2ecf20Sopenharmony_ci i_size_write(inode, cifsi->server_eof); 27768c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 27778c2ecf20Sopenharmony_ci 27788c2ecf20Sopenharmony_ci complete(&wdata->done); 27798c2ecf20Sopenharmony_ci collect_uncached_write_data(wdata->ctx); 27808c2ecf20Sopenharmony_ci /* the below call can possibly free the last ref to aio ctx */ 27818c2ecf20Sopenharmony_ci kref_put(&wdata->refcount, cifs_uncached_writedata_release); 27828c2ecf20Sopenharmony_ci} 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_cistatic int 27858c2ecf20Sopenharmony_ciwdata_fill_from_iovec(struct cifs_writedata *wdata, struct iov_iter *from, 27868c2ecf20Sopenharmony_ci size_t *len, unsigned long *num_pages) 27878c2ecf20Sopenharmony_ci{ 27888c2ecf20Sopenharmony_ci size_t save_len, copied, bytes, cur_len = *len; 27898c2ecf20Sopenharmony_ci unsigned long i, nr_pages = *num_pages; 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci save_len = cur_len; 27928c2ecf20Sopenharmony_ci for (i = 0; i < nr_pages; i++) { 27938c2ecf20Sopenharmony_ci bytes = min_t(const size_t, cur_len, PAGE_SIZE); 27948c2ecf20Sopenharmony_ci copied = copy_page_from_iter(wdata->pages[i], 0, bytes, from); 27958c2ecf20Sopenharmony_ci cur_len -= copied; 27968c2ecf20Sopenharmony_ci /* 27978c2ecf20Sopenharmony_ci * If we didn't copy as much as we expected, then that 27988c2ecf20Sopenharmony_ci * may mean we trod into an unmapped area. Stop copying 27998c2ecf20Sopenharmony_ci * at that point. On the next pass through the big 28008c2ecf20Sopenharmony_ci * loop, we'll likely end up getting a zero-length 28018c2ecf20Sopenharmony_ci * write and bailing out of it. 28028c2ecf20Sopenharmony_ci */ 28038c2ecf20Sopenharmony_ci if (copied < bytes) 28048c2ecf20Sopenharmony_ci break; 28058c2ecf20Sopenharmony_ci } 28068c2ecf20Sopenharmony_ci cur_len = save_len - cur_len; 28078c2ecf20Sopenharmony_ci *len = cur_len; 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_ci /* 28108c2ecf20Sopenharmony_ci * If we have no data to send, then that probably means that 28118c2ecf20Sopenharmony_ci * the copy above failed altogether. That's most likely because 28128c2ecf20Sopenharmony_ci * the address in the iovec was bogus. Return -EFAULT and let 28138c2ecf20Sopenharmony_ci * the caller free anything we allocated and bail out. 28148c2ecf20Sopenharmony_ci */ 28158c2ecf20Sopenharmony_ci if (!cur_len) 28168c2ecf20Sopenharmony_ci return -EFAULT; 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci /* 28198c2ecf20Sopenharmony_ci * i + 1 now represents the number of pages we actually used in 28208c2ecf20Sopenharmony_ci * the copy phase above. 28218c2ecf20Sopenharmony_ci */ 28228c2ecf20Sopenharmony_ci *num_pages = i + 1; 28238c2ecf20Sopenharmony_ci return 0; 28248c2ecf20Sopenharmony_ci} 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_cistatic int 28278c2ecf20Sopenharmony_cicifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, 28288c2ecf20Sopenharmony_ci struct cifs_aio_ctx *ctx) 28298c2ecf20Sopenharmony_ci{ 28308c2ecf20Sopenharmony_ci unsigned int wsize; 28318c2ecf20Sopenharmony_ci struct cifs_credits credits; 28328c2ecf20Sopenharmony_ci int rc; 28338c2ecf20Sopenharmony_ci struct TCP_Server_Info *server = wdata->server; 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci do { 28368c2ecf20Sopenharmony_ci if (wdata->cfile->invalidHandle) { 28378c2ecf20Sopenharmony_ci rc = cifs_reopen_file(wdata->cfile, false); 28388c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 28398c2ecf20Sopenharmony_ci continue; 28408c2ecf20Sopenharmony_ci else if (rc) 28418c2ecf20Sopenharmony_ci break; 28428c2ecf20Sopenharmony_ci } 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci /* 28468c2ecf20Sopenharmony_ci * Wait for credits to resend this wdata. 28478c2ecf20Sopenharmony_ci * Note: we are attempting to resend the whole wdata not in 28488c2ecf20Sopenharmony_ci * segments 28498c2ecf20Sopenharmony_ci */ 28508c2ecf20Sopenharmony_ci do { 28518c2ecf20Sopenharmony_ci rc = server->ops->wait_mtu_credits(server, wdata->bytes, 28528c2ecf20Sopenharmony_ci &wsize, &credits); 28538c2ecf20Sopenharmony_ci if (rc) 28548c2ecf20Sopenharmony_ci goto fail; 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci if (wsize < wdata->bytes) { 28578c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, &credits, 0); 28588c2ecf20Sopenharmony_ci msleep(1000); 28598c2ecf20Sopenharmony_ci } 28608c2ecf20Sopenharmony_ci } while (wsize < wdata->bytes); 28618c2ecf20Sopenharmony_ci wdata->credits = credits; 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci rc = adjust_credits(server, &wdata->credits, wdata->bytes); 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci if (!rc) { 28668c2ecf20Sopenharmony_ci if (wdata->cfile->invalidHandle) 28678c2ecf20Sopenharmony_ci rc = -EAGAIN; 28688c2ecf20Sopenharmony_ci else { 28698c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_SMB_DIRECT 28708c2ecf20Sopenharmony_ci if (wdata->mr) { 28718c2ecf20Sopenharmony_ci wdata->mr->need_invalidate = true; 28728c2ecf20Sopenharmony_ci smbd_deregister_mr(wdata->mr); 28738c2ecf20Sopenharmony_ci wdata->mr = NULL; 28748c2ecf20Sopenharmony_ci } 28758c2ecf20Sopenharmony_ci#endif 28768c2ecf20Sopenharmony_ci rc = server->ops->async_writev(wdata, 28778c2ecf20Sopenharmony_ci cifs_uncached_writedata_release); 28788c2ecf20Sopenharmony_ci } 28798c2ecf20Sopenharmony_ci } 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci /* If the write was successfully sent, we are done */ 28828c2ecf20Sopenharmony_ci if (!rc) { 28838c2ecf20Sopenharmony_ci list_add_tail(&wdata->list, wdata_list); 28848c2ecf20Sopenharmony_ci return 0; 28858c2ecf20Sopenharmony_ci } 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci /* Roll back credits and retry if needed */ 28888c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, &wdata->credits, 0); 28898c2ecf20Sopenharmony_ci } while (rc == -EAGAIN); 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_cifail: 28928c2ecf20Sopenharmony_ci kref_put(&wdata->refcount, cifs_uncached_writedata_release); 28938c2ecf20Sopenharmony_ci return rc; 28948c2ecf20Sopenharmony_ci} 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_cistatic int 28978c2ecf20Sopenharmony_cicifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, 28988c2ecf20Sopenharmony_ci struct cifsFileInfo *open_file, 28998c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb, struct list_head *wdata_list, 29008c2ecf20Sopenharmony_ci struct cifs_aio_ctx *ctx) 29018c2ecf20Sopenharmony_ci{ 29028c2ecf20Sopenharmony_ci int rc = 0; 29038c2ecf20Sopenharmony_ci size_t cur_len; 29048c2ecf20Sopenharmony_ci unsigned long nr_pages, num_pages, i; 29058c2ecf20Sopenharmony_ci struct cifs_writedata *wdata; 29068c2ecf20Sopenharmony_ci struct iov_iter saved_from = *from; 29078c2ecf20Sopenharmony_ci loff_t saved_offset = offset; 29088c2ecf20Sopenharmony_ci pid_t pid; 29098c2ecf20Sopenharmony_ci struct TCP_Server_Info *server; 29108c2ecf20Sopenharmony_ci struct page **pagevec; 29118c2ecf20Sopenharmony_ci size_t start; 29128c2ecf20Sopenharmony_ci unsigned int xid; 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) 29158c2ecf20Sopenharmony_ci pid = open_file->pid; 29168c2ecf20Sopenharmony_ci else 29178c2ecf20Sopenharmony_ci pid = current->tgid; 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses); 29208c2ecf20Sopenharmony_ci xid = get_xid(); 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci do { 29238c2ecf20Sopenharmony_ci unsigned int wsize; 29248c2ecf20Sopenharmony_ci struct cifs_credits credits_on_stack; 29258c2ecf20Sopenharmony_ci struct cifs_credits *credits = &credits_on_stack; 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci if (open_file->invalidHandle) { 29288c2ecf20Sopenharmony_ci rc = cifs_reopen_file(open_file, false); 29298c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 29308c2ecf20Sopenharmony_ci continue; 29318c2ecf20Sopenharmony_ci else if (rc) 29328c2ecf20Sopenharmony_ci break; 29338c2ecf20Sopenharmony_ci } 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, 29368c2ecf20Sopenharmony_ci &wsize, credits); 29378c2ecf20Sopenharmony_ci if (rc) 29388c2ecf20Sopenharmony_ci break; 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci cur_len = min_t(const size_t, len, wsize); 29418c2ecf20Sopenharmony_ci 29428c2ecf20Sopenharmony_ci if (ctx->direct_io) { 29438c2ecf20Sopenharmony_ci ssize_t result; 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci result = iov_iter_get_pages_alloc( 29468c2ecf20Sopenharmony_ci from, &pagevec, cur_len, &start); 29478c2ecf20Sopenharmony_ci if (result < 0) { 29488c2ecf20Sopenharmony_ci cifs_dbg(VFS, 29498c2ecf20Sopenharmony_ci "direct_writev couldn't get user pages (rc=%zd) iter type %d iov_offset %zd count %zd\n", 29508c2ecf20Sopenharmony_ci result, iov_iter_type(from), 29518c2ecf20Sopenharmony_ci from->iov_offset, from->count); 29528c2ecf20Sopenharmony_ci dump_stack(); 29538c2ecf20Sopenharmony_ci 29548c2ecf20Sopenharmony_ci rc = result; 29558c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 29568c2ecf20Sopenharmony_ci break; 29578c2ecf20Sopenharmony_ci } 29588c2ecf20Sopenharmony_ci cur_len = (size_t)result; 29598c2ecf20Sopenharmony_ci iov_iter_advance(from, cur_len); 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci nr_pages = 29628c2ecf20Sopenharmony_ci (cur_len + start + PAGE_SIZE - 1) / PAGE_SIZE; 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci wdata = cifs_writedata_direct_alloc(pagevec, 29658c2ecf20Sopenharmony_ci cifs_uncached_writev_complete); 29668c2ecf20Sopenharmony_ci if (!wdata) { 29678c2ecf20Sopenharmony_ci rc = -ENOMEM; 29688c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 29698c2ecf20Sopenharmony_ci break; 29708c2ecf20Sopenharmony_ci } 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci wdata->page_offset = start; 29748c2ecf20Sopenharmony_ci wdata->tailsz = 29758c2ecf20Sopenharmony_ci nr_pages > 1 ? 29768c2ecf20Sopenharmony_ci cur_len - (PAGE_SIZE - start) - 29778c2ecf20Sopenharmony_ci (nr_pages - 2) * PAGE_SIZE : 29788c2ecf20Sopenharmony_ci cur_len; 29798c2ecf20Sopenharmony_ci } else { 29808c2ecf20Sopenharmony_ci nr_pages = get_numpages(wsize, len, &cur_len); 29818c2ecf20Sopenharmony_ci wdata = cifs_writedata_alloc(nr_pages, 29828c2ecf20Sopenharmony_ci cifs_uncached_writev_complete); 29838c2ecf20Sopenharmony_ci if (!wdata) { 29848c2ecf20Sopenharmony_ci rc = -ENOMEM; 29858c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 29868c2ecf20Sopenharmony_ci break; 29878c2ecf20Sopenharmony_ci } 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_ci rc = cifs_write_allocate_pages(wdata->pages, nr_pages); 29908c2ecf20Sopenharmony_ci if (rc) { 29918c2ecf20Sopenharmony_ci kvfree(wdata->pages); 29928c2ecf20Sopenharmony_ci kfree(wdata); 29938c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 29948c2ecf20Sopenharmony_ci break; 29958c2ecf20Sopenharmony_ci } 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci num_pages = nr_pages; 29988c2ecf20Sopenharmony_ci rc = wdata_fill_from_iovec( 29998c2ecf20Sopenharmony_ci wdata, from, &cur_len, &num_pages); 30008c2ecf20Sopenharmony_ci if (rc) { 30018c2ecf20Sopenharmony_ci for (i = 0; i < nr_pages; i++) 30028c2ecf20Sopenharmony_ci put_page(wdata->pages[i]); 30038c2ecf20Sopenharmony_ci kvfree(wdata->pages); 30048c2ecf20Sopenharmony_ci kfree(wdata); 30058c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 30068c2ecf20Sopenharmony_ci break; 30078c2ecf20Sopenharmony_ci } 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci /* 30108c2ecf20Sopenharmony_ci * Bring nr_pages down to the number of pages we 30118c2ecf20Sopenharmony_ci * actually used, and free any pages that we didn't use. 30128c2ecf20Sopenharmony_ci */ 30138c2ecf20Sopenharmony_ci for ( ; nr_pages > num_pages; nr_pages--) 30148c2ecf20Sopenharmony_ci put_page(wdata->pages[nr_pages - 1]); 30158c2ecf20Sopenharmony_ci 30168c2ecf20Sopenharmony_ci wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE); 30178c2ecf20Sopenharmony_ci } 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci wdata->sync_mode = WB_SYNC_ALL; 30208c2ecf20Sopenharmony_ci wdata->nr_pages = nr_pages; 30218c2ecf20Sopenharmony_ci wdata->offset = (__u64)offset; 30228c2ecf20Sopenharmony_ci wdata->cfile = cifsFileInfo_get(open_file); 30238c2ecf20Sopenharmony_ci wdata->server = server; 30248c2ecf20Sopenharmony_ci wdata->pid = pid; 30258c2ecf20Sopenharmony_ci wdata->bytes = cur_len; 30268c2ecf20Sopenharmony_ci wdata->pagesz = PAGE_SIZE; 30278c2ecf20Sopenharmony_ci wdata->credits = credits_on_stack; 30288c2ecf20Sopenharmony_ci wdata->ctx = ctx; 30298c2ecf20Sopenharmony_ci kref_get(&ctx->refcount); 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci rc = adjust_credits(server, &wdata->credits, wdata->bytes); 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci if (!rc) { 30348c2ecf20Sopenharmony_ci if (wdata->cfile->invalidHandle) 30358c2ecf20Sopenharmony_ci rc = -EAGAIN; 30368c2ecf20Sopenharmony_ci else 30378c2ecf20Sopenharmony_ci rc = server->ops->async_writev(wdata, 30388c2ecf20Sopenharmony_ci cifs_uncached_writedata_release); 30398c2ecf20Sopenharmony_ci } 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci if (rc) { 30428c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, &wdata->credits, 0); 30438c2ecf20Sopenharmony_ci kref_put(&wdata->refcount, 30448c2ecf20Sopenharmony_ci cifs_uncached_writedata_release); 30458c2ecf20Sopenharmony_ci if (rc == -EAGAIN) { 30468c2ecf20Sopenharmony_ci *from = saved_from; 30478c2ecf20Sopenharmony_ci iov_iter_advance(from, offset - saved_offset); 30488c2ecf20Sopenharmony_ci continue; 30498c2ecf20Sopenharmony_ci } 30508c2ecf20Sopenharmony_ci break; 30518c2ecf20Sopenharmony_ci } 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci list_add_tail(&wdata->list, wdata_list); 30548c2ecf20Sopenharmony_ci offset += cur_len; 30558c2ecf20Sopenharmony_ci len -= cur_len; 30568c2ecf20Sopenharmony_ci } while (len > 0); 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci free_xid(xid); 30598c2ecf20Sopenharmony_ci return rc; 30608c2ecf20Sopenharmony_ci} 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_cistatic void collect_uncached_write_data(struct cifs_aio_ctx *ctx) 30638c2ecf20Sopenharmony_ci{ 30648c2ecf20Sopenharmony_ci struct cifs_writedata *wdata, *tmp; 30658c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 30668c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb; 30678c2ecf20Sopenharmony_ci struct dentry *dentry = ctx->cfile->dentry; 30688c2ecf20Sopenharmony_ci ssize_t rc; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci tcon = tlink_tcon(ctx->cfile->tlink); 30718c2ecf20Sopenharmony_ci cifs_sb = CIFS_SB(dentry->d_sb); 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci mutex_lock(&ctx->aio_mutex); 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci if (list_empty(&ctx->list)) { 30768c2ecf20Sopenharmony_ci mutex_unlock(&ctx->aio_mutex); 30778c2ecf20Sopenharmony_ci return; 30788c2ecf20Sopenharmony_ci } 30798c2ecf20Sopenharmony_ci 30808c2ecf20Sopenharmony_ci rc = ctx->rc; 30818c2ecf20Sopenharmony_ci /* 30828c2ecf20Sopenharmony_ci * Wait for and collect replies for any successful sends in order of 30838c2ecf20Sopenharmony_ci * increasing offset. Once an error is hit, then return without waiting 30848c2ecf20Sopenharmony_ci * for any more replies. 30858c2ecf20Sopenharmony_ci */ 30868c2ecf20Sopenharmony_cirestart_loop: 30878c2ecf20Sopenharmony_ci list_for_each_entry_safe(wdata, tmp, &ctx->list, list) { 30888c2ecf20Sopenharmony_ci if (!rc) { 30898c2ecf20Sopenharmony_ci if (!try_wait_for_completion(&wdata->done)) { 30908c2ecf20Sopenharmony_ci mutex_unlock(&ctx->aio_mutex); 30918c2ecf20Sopenharmony_ci return; 30928c2ecf20Sopenharmony_ci } 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci if (wdata->result) 30958c2ecf20Sopenharmony_ci rc = wdata->result; 30968c2ecf20Sopenharmony_ci else 30978c2ecf20Sopenharmony_ci ctx->total_len += wdata->bytes; 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci /* resend call if it's a retryable error */ 31008c2ecf20Sopenharmony_ci if (rc == -EAGAIN) { 31018c2ecf20Sopenharmony_ci struct list_head tmp_list; 31028c2ecf20Sopenharmony_ci struct iov_iter tmp_from = ctx->iter; 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tmp_list); 31058c2ecf20Sopenharmony_ci list_del_init(&wdata->list); 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_ci if (ctx->direct_io) 31088c2ecf20Sopenharmony_ci rc = cifs_resend_wdata( 31098c2ecf20Sopenharmony_ci wdata, &tmp_list, ctx); 31108c2ecf20Sopenharmony_ci else { 31118c2ecf20Sopenharmony_ci iov_iter_advance(&tmp_from, 31128c2ecf20Sopenharmony_ci wdata->offset - ctx->pos); 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci rc = cifs_write_from_iter(wdata->offset, 31158c2ecf20Sopenharmony_ci wdata->bytes, &tmp_from, 31168c2ecf20Sopenharmony_ci ctx->cfile, cifs_sb, &tmp_list, 31178c2ecf20Sopenharmony_ci ctx); 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci kref_put(&wdata->refcount, 31208c2ecf20Sopenharmony_ci cifs_uncached_writedata_release); 31218c2ecf20Sopenharmony_ci } 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci list_splice(&tmp_list, &ctx->list); 31248c2ecf20Sopenharmony_ci goto restart_loop; 31258c2ecf20Sopenharmony_ci } 31268c2ecf20Sopenharmony_ci } 31278c2ecf20Sopenharmony_ci list_del_init(&wdata->list); 31288c2ecf20Sopenharmony_ci kref_put(&wdata->refcount, cifs_uncached_writedata_release); 31298c2ecf20Sopenharmony_ci } 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci cifs_stats_bytes_written(tcon, ctx->total_len); 31328c2ecf20Sopenharmony_ci set_bit(CIFS_INO_INVALID_MAPPING, &CIFS_I(dentry->d_inode)->flags); 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci ctx->rc = (rc == 0) ? ctx->total_len : rc; 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci mutex_unlock(&ctx->aio_mutex); 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci if (ctx->iocb && ctx->iocb->ki_complete) 31398c2ecf20Sopenharmony_ci ctx->iocb->ki_complete(ctx->iocb, ctx->rc, 0); 31408c2ecf20Sopenharmony_ci else 31418c2ecf20Sopenharmony_ci complete(&ctx->done); 31428c2ecf20Sopenharmony_ci} 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_cistatic ssize_t __cifs_writev( 31458c2ecf20Sopenharmony_ci struct kiocb *iocb, struct iov_iter *from, bool direct) 31468c2ecf20Sopenharmony_ci{ 31478c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 31488c2ecf20Sopenharmony_ci ssize_t total_written = 0; 31498c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile; 31508c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 31518c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb; 31528c2ecf20Sopenharmony_ci struct cifs_aio_ctx *ctx; 31538c2ecf20Sopenharmony_ci struct iov_iter saved_from = *from; 31548c2ecf20Sopenharmony_ci size_t len = iov_iter_count(from); 31558c2ecf20Sopenharmony_ci int rc; 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci /* 31588c2ecf20Sopenharmony_ci * iov_iter_get_pages_alloc doesn't work with ITER_KVEC. 31598c2ecf20Sopenharmony_ci * In this case, fall back to non-direct write function. 31608c2ecf20Sopenharmony_ci * this could be improved by getting pages directly in ITER_KVEC 31618c2ecf20Sopenharmony_ci */ 31628c2ecf20Sopenharmony_ci if (direct && iov_iter_is_kvec(from)) { 31638c2ecf20Sopenharmony_ci cifs_dbg(FYI, "use non-direct cifs_writev for kvec I/O\n"); 31648c2ecf20Sopenharmony_ci direct = false; 31658c2ecf20Sopenharmony_ci } 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci rc = generic_write_checks(iocb, from); 31688c2ecf20Sopenharmony_ci if (rc <= 0) 31698c2ecf20Sopenharmony_ci return rc; 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci cifs_sb = CIFS_FILE_SB(file); 31728c2ecf20Sopenharmony_ci cfile = file->private_data; 31738c2ecf20Sopenharmony_ci tcon = tlink_tcon(cfile->tlink); 31748c2ecf20Sopenharmony_ci 31758c2ecf20Sopenharmony_ci if (!tcon->ses->server->ops->async_writev) 31768c2ecf20Sopenharmony_ci return -ENOSYS; 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci ctx = cifs_aio_ctx_alloc(); 31798c2ecf20Sopenharmony_ci if (!ctx) 31808c2ecf20Sopenharmony_ci return -ENOMEM; 31818c2ecf20Sopenharmony_ci 31828c2ecf20Sopenharmony_ci ctx->cfile = cifsFileInfo_get(cfile); 31838c2ecf20Sopenharmony_ci 31848c2ecf20Sopenharmony_ci if (!is_sync_kiocb(iocb)) 31858c2ecf20Sopenharmony_ci ctx->iocb = iocb; 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci ctx->pos = iocb->ki_pos; 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci if (direct) { 31908c2ecf20Sopenharmony_ci ctx->direct_io = true; 31918c2ecf20Sopenharmony_ci ctx->iter = *from; 31928c2ecf20Sopenharmony_ci ctx->len = len; 31938c2ecf20Sopenharmony_ci } else { 31948c2ecf20Sopenharmony_ci rc = setup_aio_ctx_iter(ctx, from, WRITE); 31958c2ecf20Sopenharmony_ci if (rc) { 31968c2ecf20Sopenharmony_ci kref_put(&ctx->refcount, cifs_aio_ctx_release); 31978c2ecf20Sopenharmony_ci return rc; 31988c2ecf20Sopenharmony_ci } 31998c2ecf20Sopenharmony_ci } 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci /* grab a lock here due to read response handlers can access ctx */ 32028c2ecf20Sopenharmony_ci mutex_lock(&ctx->aio_mutex); 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci rc = cifs_write_from_iter(iocb->ki_pos, ctx->len, &saved_from, 32058c2ecf20Sopenharmony_ci cfile, cifs_sb, &ctx->list, ctx); 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci /* 32088c2ecf20Sopenharmony_ci * If at least one write was successfully sent, then discard any rc 32098c2ecf20Sopenharmony_ci * value from the later writes. If the other write succeeds, then 32108c2ecf20Sopenharmony_ci * we'll end up returning whatever was written. If it fails, then 32118c2ecf20Sopenharmony_ci * we'll get a new rc value from that. 32128c2ecf20Sopenharmony_ci */ 32138c2ecf20Sopenharmony_ci if (!list_empty(&ctx->list)) 32148c2ecf20Sopenharmony_ci rc = 0; 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci mutex_unlock(&ctx->aio_mutex); 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ci if (rc) { 32198c2ecf20Sopenharmony_ci kref_put(&ctx->refcount, cifs_aio_ctx_release); 32208c2ecf20Sopenharmony_ci return rc; 32218c2ecf20Sopenharmony_ci } 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci if (!is_sync_kiocb(iocb)) { 32248c2ecf20Sopenharmony_ci kref_put(&ctx->refcount, cifs_aio_ctx_release); 32258c2ecf20Sopenharmony_ci return -EIOCBQUEUED; 32268c2ecf20Sopenharmony_ci } 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci rc = wait_for_completion_killable(&ctx->done); 32298c2ecf20Sopenharmony_ci if (rc) { 32308c2ecf20Sopenharmony_ci mutex_lock(&ctx->aio_mutex); 32318c2ecf20Sopenharmony_ci ctx->rc = rc = -EINTR; 32328c2ecf20Sopenharmony_ci total_written = ctx->total_len; 32338c2ecf20Sopenharmony_ci mutex_unlock(&ctx->aio_mutex); 32348c2ecf20Sopenharmony_ci } else { 32358c2ecf20Sopenharmony_ci rc = ctx->rc; 32368c2ecf20Sopenharmony_ci total_written = ctx->total_len; 32378c2ecf20Sopenharmony_ci } 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci kref_put(&ctx->refcount, cifs_aio_ctx_release); 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci if (unlikely(!total_written)) 32428c2ecf20Sopenharmony_ci return rc; 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_ci iocb->ki_pos += total_written; 32458c2ecf20Sopenharmony_ci return total_written; 32468c2ecf20Sopenharmony_ci} 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_cissize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter *from) 32498c2ecf20Sopenharmony_ci{ 32508c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 32518c2ecf20Sopenharmony_ci 32528c2ecf20Sopenharmony_ci cifs_revalidate_mapping(file->f_inode); 32538c2ecf20Sopenharmony_ci return __cifs_writev(iocb, from, true); 32548c2ecf20Sopenharmony_ci} 32558c2ecf20Sopenharmony_ci 32568c2ecf20Sopenharmony_cissize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from) 32578c2ecf20Sopenharmony_ci{ 32588c2ecf20Sopenharmony_ci return __cifs_writev(iocb, from, false); 32598c2ecf20Sopenharmony_ci} 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_cistatic ssize_t 32628c2ecf20Sopenharmony_cicifs_writev(struct kiocb *iocb, struct iov_iter *from) 32638c2ecf20Sopenharmony_ci{ 32648c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 32658c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data; 32668c2ecf20Sopenharmony_ci struct inode *inode = file->f_mapping->host; 32678c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(inode); 32688c2ecf20Sopenharmony_ci struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; 32698c2ecf20Sopenharmony_ci ssize_t rc; 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci inode_lock(inode); 32728c2ecf20Sopenharmony_ci /* 32738c2ecf20Sopenharmony_ci * We need to hold the sem to be sure nobody modifies lock list 32748c2ecf20Sopenharmony_ci * with a brlock that prevents writing. 32758c2ecf20Sopenharmony_ci */ 32768c2ecf20Sopenharmony_ci down_read(&cinode->lock_sem); 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_ci rc = generic_write_checks(iocb, from); 32798c2ecf20Sopenharmony_ci if (rc <= 0) 32808c2ecf20Sopenharmony_ci goto out; 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(from), 32838c2ecf20Sopenharmony_ci server->vals->exclusive_lock_type, 0, 32848c2ecf20Sopenharmony_ci NULL, CIFS_WRITE_OP)) 32858c2ecf20Sopenharmony_ci rc = __generic_file_write_iter(iocb, from); 32868c2ecf20Sopenharmony_ci else 32878c2ecf20Sopenharmony_ci rc = -EACCES; 32888c2ecf20Sopenharmony_ciout: 32898c2ecf20Sopenharmony_ci up_read(&cinode->lock_sem); 32908c2ecf20Sopenharmony_ci inode_unlock(inode); 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci if (rc > 0) 32938c2ecf20Sopenharmony_ci rc = generic_write_sync(iocb, rc); 32948c2ecf20Sopenharmony_ci return rc; 32958c2ecf20Sopenharmony_ci} 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_cissize_t 32988c2ecf20Sopenharmony_cicifs_strict_writev(struct kiocb *iocb, struct iov_iter *from) 32998c2ecf20Sopenharmony_ci{ 33008c2ecf20Sopenharmony_ci struct inode *inode = file_inode(iocb->ki_filp); 33018c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(inode); 33028c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 33038c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile = (struct cifsFileInfo *) 33048c2ecf20Sopenharmony_ci iocb->ki_filp->private_data; 33058c2ecf20Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 33068c2ecf20Sopenharmony_ci ssize_t written; 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci written = cifs_get_writer(cinode); 33098c2ecf20Sopenharmony_ci if (written) 33108c2ecf20Sopenharmony_ci return written; 33118c2ecf20Sopenharmony_ci 33128c2ecf20Sopenharmony_ci if (CIFS_CACHE_WRITE(cinode)) { 33138c2ecf20Sopenharmony_ci if (cap_unix(tcon->ses) && 33148c2ecf20Sopenharmony_ci (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) 33158c2ecf20Sopenharmony_ci && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) { 33168c2ecf20Sopenharmony_ci written = generic_file_write_iter(iocb, from); 33178c2ecf20Sopenharmony_ci goto out; 33188c2ecf20Sopenharmony_ci } 33198c2ecf20Sopenharmony_ci written = cifs_writev(iocb, from); 33208c2ecf20Sopenharmony_ci goto out; 33218c2ecf20Sopenharmony_ci } 33228c2ecf20Sopenharmony_ci /* 33238c2ecf20Sopenharmony_ci * For non-oplocked files in strict cache mode we need to write the data 33248c2ecf20Sopenharmony_ci * to the server exactly from the pos to pos+len-1 rather than flush all 33258c2ecf20Sopenharmony_ci * affected pages because it may cause a error with mandatory locks on 33268c2ecf20Sopenharmony_ci * these pages but not on the region from pos to ppos+len-1. 33278c2ecf20Sopenharmony_ci */ 33288c2ecf20Sopenharmony_ci written = cifs_user_writev(iocb, from); 33298c2ecf20Sopenharmony_ci if (CIFS_CACHE_READ(cinode)) { 33308c2ecf20Sopenharmony_ci /* 33318c2ecf20Sopenharmony_ci * We have read level caching and we have just sent a write 33328c2ecf20Sopenharmony_ci * request to the server thus making data in the cache stale. 33338c2ecf20Sopenharmony_ci * Zap the cache and set oplock/lease level to NONE to avoid 33348c2ecf20Sopenharmony_ci * reading stale data from the cache. All subsequent read 33358c2ecf20Sopenharmony_ci * operations will read new data from the server. 33368c2ecf20Sopenharmony_ci */ 33378c2ecf20Sopenharmony_ci cifs_zap_mapping(inode); 33388c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Set Oplock/Lease to NONE for inode=%p after write\n", 33398c2ecf20Sopenharmony_ci inode); 33408c2ecf20Sopenharmony_ci cinode->oplock = 0; 33418c2ecf20Sopenharmony_ci } 33428c2ecf20Sopenharmony_ciout: 33438c2ecf20Sopenharmony_ci cifs_put_writer(cinode); 33448c2ecf20Sopenharmony_ci return written; 33458c2ecf20Sopenharmony_ci} 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_cistatic struct cifs_readdata * 33488c2ecf20Sopenharmony_cicifs_readdata_direct_alloc(struct page **pages, work_func_t complete) 33498c2ecf20Sopenharmony_ci{ 33508c2ecf20Sopenharmony_ci struct cifs_readdata *rdata; 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_ci rdata = kzalloc(sizeof(*rdata), GFP_KERNEL); 33538c2ecf20Sopenharmony_ci if (rdata != NULL) { 33548c2ecf20Sopenharmony_ci rdata->pages = pages; 33558c2ecf20Sopenharmony_ci kref_init(&rdata->refcount); 33568c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rdata->list); 33578c2ecf20Sopenharmony_ci init_completion(&rdata->done); 33588c2ecf20Sopenharmony_ci INIT_WORK(&rdata->work, complete); 33598c2ecf20Sopenharmony_ci } 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci return rdata; 33628c2ecf20Sopenharmony_ci} 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_cistatic struct cifs_readdata * 33658c2ecf20Sopenharmony_cicifs_readdata_alloc(unsigned int nr_pages, work_func_t complete) 33668c2ecf20Sopenharmony_ci{ 33678c2ecf20Sopenharmony_ci struct page **pages = 33688c2ecf20Sopenharmony_ci kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL); 33698c2ecf20Sopenharmony_ci struct cifs_readdata *ret = NULL; 33708c2ecf20Sopenharmony_ci 33718c2ecf20Sopenharmony_ci if (pages) { 33728c2ecf20Sopenharmony_ci ret = cifs_readdata_direct_alloc(pages, complete); 33738c2ecf20Sopenharmony_ci if (!ret) 33748c2ecf20Sopenharmony_ci kfree(pages); 33758c2ecf20Sopenharmony_ci } 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci return ret; 33788c2ecf20Sopenharmony_ci} 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_civoid 33818c2ecf20Sopenharmony_cicifs_readdata_release(struct kref *refcount) 33828c2ecf20Sopenharmony_ci{ 33838c2ecf20Sopenharmony_ci struct cifs_readdata *rdata = container_of(refcount, 33848c2ecf20Sopenharmony_ci struct cifs_readdata, refcount); 33858c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_SMB_DIRECT 33868c2ecf20Sopenharmony_ci if (rdata->mr) { 33878c2ecf20Sopenharmony_ci smbd_deregister_mr(rdata->mr); 33888c2ecf20Sopenharmony_ci rdata->mr = NULL; 33898c2ecf20Sopenharmony_ci } 33908c2ecf20Sopenharmony_ci#endif 33918c2ecf20Sopenharmony_ci if (rdata->cfile) 33928c2ecf20Sopenharmony_ci cifsFileInfo_put(rdata->cfile); 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci kvfree(rdata->pages); 33958c2ecf20Sopenharmony_ci kfree(rdata); 33968c2ecf20Sopenharmony_ci} 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_cistatic int 33998c2ecf20Sopenharmony_cicifs_read_allocate_pages(struct cifs_readdata *rdata, unsigned int nr_pages) 34008c2ecf20Sopenharmony_ci{ 34018c2ecf20Sopenharmony_ci int rc = 0; 34028c2ecf20Sopenharmony_ci struct page *page; 34038c2ecf20Sopenharmony_ci unsigned int i; 34048c2ecf20Sopenharmony_ci 34058c2ecf20Sopenharmony_ci for (i = 0; i < nr_pages; i++) { 34068c2ecf20Sopenharmony_ci page = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); 34078c2ecf20Sopenharmony_ci if (!page) { 34088c2ecf20Sopenharmony_ci rc = -ENOMEM; 34098c2ecf20Sopenharmony_ci break; 34108c2ecf20Sopenharmony_ci } 34118c2ecf20Sopenharmony_ci rdata->pages[i] = page; 34128c2ecf20Sopenharmony_ci } 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci if (rc) { 34158c2ecf20Sopenharmony_ci unsigned int nr_page_failed = i; 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_ci for (i = 0; i < nr_page_failed; i++) { 34188c2ecf20Sopenharmony_ci put_page(rdata->pages[i]); 34198c2ecf20Sopenharmony_ci rdata->pages[i] = NULL; 34208c2ecf20Sopenharmony_ci } 34218c2ecf20Sopenharmony_ci } 34228c2ecf20Sopenharmony_ci return rc; 34238c2ecf20Sopenharmony_ci} 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_cistatic void 34268c2ecf20Sopenharmony_cicifs_uncached_readdata_release(struct kref *refcount) 34278c2ecf20Sopenharmony_ci{ 34288c2ecf20Sopenharmony_ci struct cifs_readdata *rdata = container_of(refcount, 34298c2ecf20Sopenharmony_ci struct cifs_readdata, refcount); 34308c2ecf20Sopenharmony_ci unsigned int i; 34318c2ecf20Sopenharmony_ci 34328c2ecf20Sopenharmony_ci kref_put(&rdata->ctx->refcount, cifs_aio_ctx_release); 34338c2ecf20Sopenharmony_ci for (i = 0; i < rdata->nr_pages; i++) { 34348c2ecf20Sopenharmony_ci put_page(rdata->pages[i]); 34358c2ecf20Sopenharmony_ci } 34368c2ecf20Sopenharmony_ci cifs_readdata_release(refcount); 34378c2ecf20Sopenharmony_ci} 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci/** 34408c2ecf20Sopenharmony_ci * cifs_readdata_to_iov - copy data from pages in response to an iovec 34418c2ecf20Sopenharmony_ci * @rdata: the readdata response with list of pages holding data 34428c2ecf20Sopenharmony_ci * @iter: destination for our data 34438c2ecf20Sopenharmony_ci * 34448c2ecf20Sopenharmony_ci * This function copies data from a list of pages in a readdata response into 34458c2ecf20Sopenharmony_ci * an array of iovecs. It will first calculate where the data should go 34468c2ecf20Sopenharmony_ci * based on the info in the readdata and then copy the data into that spot. 34478c2ecf20Sopenharmony_ci */ 34488c2ecf20Sopenharmony_cistatic int 34498c2ecf20Sopenharmony_cicifs_readdata_to_iov(struct cifs_readdata *rdata, struct iov_iter *iter) 34508c2ecf20Sopenharmony_ci{ 34518c2ecf20Sopenharmony_ci size_t remaining = rdata->got_bytes; 34528c2ecf20Sopenharmony_ci unsigned int i; 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci for (i = 0; i < rdata->nr_pages; i++) { 34558c2ecf20Sopenharmony_ci struct page *page = rdata->pages[i]; 34568c2ecf20Sopenharmony_ci size_t copy = min_t(size_t, remaining, PAGE_SIZE); 34578c2ecf20Sopenharmony_ci size_t written; 34588c2ecf20Sopenharmony_ci 34598c2ecf20Sopenharmony_ci if (unlikely(iov_iter_is_pipe(iter))) { 34608c2ecf20Sopenharmony_ci void *addr = kmap_atomic(page); 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_ci written = copy_to_iter(addr, copy, iter); 34638c2ecf20Sopenharmony_ci kunmap_atomic(addr); 34648c2ecf20Sopenharmony_ci } else 34658c2ecf20Sopenharmony_ci written = copy_page_to_iter(page, 0, copy, iter); 34668c2ecf20Sopenharmony_ci remaining -= written; 34678c2ecf20Sopenharmony_ci if (written < copy && iov_iter_count(iter) > 0) 34688c2ecf20Sopenharmony_ci break; 34698c2ecf20Sopenharmony_ci } 34708c2ecf20Sopenharmony_ci return remaining ? -EFAULT : 0; 34718c2ecf20Sopenharmony_ci} 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_cistatic void collect_uncached_read_data(struct cifs_aio_ctx *ctx); 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_cistatic void 34768c2ecf20Sopenharmony_cicifs_uncached_readv_complete(struct work_struct *work) 34778c2ecf20Sopenharmony_ci{ 34788c2ecf20Sopenharmony_ci struct cifs_readdata *rdata = container_of(work, 34798c2ecf20Sopenharmony_ci struct cifs_readdata, work); 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci complete(&rdata->done); 34828c2ecf20Sopenharmony_ci collect_uncached_read_data(rdata->ctx); 34838c2ecf20Sopenharmony_ci /* the below call can possibly free the last ref to aio ctx */ 34848c2ecf20Sopenharmony_ci kref_put(&rdata->refcount, cifs_uncached_readdata_release); 34858c2ecf20Sopenharmony_ci} 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_cistatic int 34888c2ecf20Sopenharmony_ciuncached_fill_pages(struct TCP_Server_Info *server, 34898c2ecf20Sopenharmony_ci struct cifs_readdata *rdata, struct iov_iter *iter, 34908c2ecf20Sopenharmony_ci unsigned int len) 34918c2ecf20Sopenharmony_ci{ 34928c2ecf20Sopenharmony_ci int result = 0; 34938c2ecf20Sopenharmony_ci unsigned int i; 34948c2ecf20Sopenharmony_ci unsigned int nr_pages = rdata->nr_pages; 34958c2ecf20Sopenharmony_ci unsigned int page_offset = rdata->page_offset; 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci rdata->got_bytes = 0; 34988c2ecf20Sopenharmony_ci rdata->tailsz = PAGE_SIZE; 34998c2ecf20Sopenharmony_ci for (i = 0; i < nr_pages; i++) { 35008c2ecf20Sopenharmony_ci struct page *page = rdata->pages[i]; 35018c2ecf20Sopenharmony_ci size_t n; 35028c2ecf20Sopenharmony_ci unsigned int segment_size = rdata->pagesz; 35038c2ecf20Sopenharmony_ci 35048c2ecf20Sopenharmony_ci if (i == 0) 35058c2ecf20Sopenharmony_ci segment_size -= page_offset; 35068c2ecf20Sopenharmony_ci else 35078c2ecf20Sopenharmony_ci page_offset = 0; 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_ci if (len <= 0) { 35118c2ecf20Sopenharmony_ci /* no need to hold page hostage */ 35128c2ecf20Sopenharmony_ci rdata->pages[i] = NULL; 35138c2ecf20Sopenharmony_ci rdata->nr_pages--; 35148c2ecf20Sopenharmony_ci put_page(page); 35158c2ecf20Sopenharmony_ci continue; 35168c2ecf20Sopenharmony_ci } 35178c2ecf20Sopenharmony_ci 35188c2ecf20Sopenharmony_ci n = len; 35198c2ecf20Sopenharmony_ci if (len >= segment_size) 35208c2ecf20Sopenharmony_ci /* enough data to fill the page */ 35218c2ecf20Sopenharmony_ci n = segment_size; 35228c2ecf20Sopenharmony_ci else 35238c2ecf20Sopenharmony_ci rdata->tailsz = len; 35248c2ecf20Sopenharmony_ci len -= n; 35258c2ecf20Sopenharmony_ci 35268c2ecf20Sopenharmony_ci if (iter) 35278c2ecf20Sopenharmony_ci result = copy_page_from_iter( 35288c2ecf20Sopenharmony_ci page, page_offset, n, iter); 35298c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_SMB_DIRECT 35308c2ecf20Sopenharmony_ci else if (rdata->mr) 35318c2ecf20Sopenharmony_ci result = n; 35328c2ecf20Sopenharmony_ci#endif 35338c2ecf20Sopenharmony_ci else 35348c2ecf20Sopenharmony_ci result = cifs_read_page_from_socket( 35358c2ecf20Sopenharmony_ci server, page, page_offset, n); 35368c2ecf20Sopenharmony_ci if (result < 0) 35378c2ecf20Sopenharmony_ci break; 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_ci rdata->got_bytes += result; 35408c2ecf20Sopenharmony_ci } 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci return result != -ECONNABORTED && rdata->got_bytes > 0 ? 35438c2ecf20Sopenharmony_ci rdata->got_bytes : result; 35448c2ecf20Sopenharmony_ci} 35458c2ecf20Sopenharmony_ci 35468c2ecf20Sopenharmony_cistatic int 35478c2ecf20Sopenharmony_cicifs_uncached_read_into_pages(struct TCP_Server_Info *server, 35488c2ecf20Sopenharmony_ci struct cifs_readdata *rdata, unsigned int len) 35498c2ecf20Sopenharmony_ci{ 35508c2ecf20Sopenharmony_ci return uncached_fill_pages(server, rdata, NULL, len); 35518c2ecf20Sopenharmony_ci} 35528c2ecf20Sopenharmony_ci 35538c2ecf20Sopenharmony_cistatic int 35548c2ecf20Sopenharmony_cicifs_uncached_copy_into_pages(struct TCP_Server_Info *server, 35558c2ecf20Sopenharmony_ci struct cifs_readdata *rdata, 35568c2ecf20Sopenharmony_ci struct iov_iter *iter) 35578c2ecf20Sopenharmony_ci{ 35588c2ecf20Sopenharmony_ci return uncached_fill_pages(server, rdata, iter, iter->count); 35598c2ecf20Sopenharmony_ci} 35608c2ecf20Sopenharmony_ci 35618c2ecf20Sopenharmony_cistatic int cifs_resend_rdata(struct cifs_readdata *rdata, 35628c2ecf20Sopenharmony_ci struct list_head *rdata_list, 35638c2ecf20Sopenharmony_ci struct cifs_aio_ctx *ctx) 35648c2ecf20Sopenharmony_ci{ 35658c2ecf20Sopenharmony_ci unsigned int rsize; 35668c2ecf20Sopenharmony_ci struct cifs_credits credits; 35678c2ecf20Sopenharmony_ci int rc; 35688c2ecf20Sopenharmony_ci struct TCP_Server_Info *server; 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_ci /* XXX: should we pick a new channel here? */ 35718c2ecf20Sopenharmony_ci server = rdata->server; 35728c2ecf20Sopenharmony_ci 35738c2ecf20Sopenharmony_ci do { 35748c2ecf20Sopenharmony_ci if (rdata->cfile->invalidHandle) { 35758c2ecf20Sopenharmony_ci rc = cifs_reopen_file(rdata->cfile, true); 35768c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 35778c2ecf20Sopenharmony_ci continue; 35788c2ecf20Sopenharmony_ci else if (rc) 35798c2ecf20Sopenharmony_ci break; 35808c2ecf20Sopenharmony_ci } 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ci /* 35838c2ecf20Sopenharmony_ci * Wait for credits to resend this rdata. 35848c2ecf20Sopenharmony_ci * Note: we are attempting to resend the whole rdata not in 35858c2ecf20Sopenharmony_ci * segments 35868c2ecf20Sopenharmony_ci */ 35878c2ecf20Sopenharmony_ci do { 35888c2ecf20Sopenharmony_ci rc = server->ops->wait_mtu_credits(server, rdata->bytes, 35898c2ecf20Sopenharmony_ci &rsize, &credits); 35908c2ecf20Sopenharmony_ci 35918c2ecf20Sopenharmony_ci if (rc) 35928c2ecf20Sopenharmony_ci goto fail; 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci if (rsize < rdata->bytes) { 35958c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, &credits, 0); 35968c2ecf20Sopenharmony_ci msleep(1000); 35978c2ecf20Sopenharmony_ci } 35988c2ecf20Sopenharmony_ci } while (rsize < rdata->bytes); 35998c2ecf20Sopenharmony_ci rdata->credits = credits; 36008c2ecf20Sopenharmony_ci 36018c2ecf20Sopenharmony_ci rc = adjust_credits(server, &rdata->credits, rdata->bytes); 36028c2ecf20Sopenharmony_ci if (!rc) { 36038c2ecf20Sopenharmony_ci if (rdata->cfile->invalidHandle) 36048c2ecf20Sopenharmony_ci rc = -EAGAIN; 36058c2ecf20Sopenharmony_ci else { 36068c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_SMB_DIRECT 36078c2ecf20Sopenharmony_ci if (rdata->mr) { 36088c2ecf20Sopenharmony_ci rdata->mr->need_invalidate = true; 36098c2ecf20Sopenharmony_ci smbd_deregister_mr(rdata->mr); 36108c2ecf20Sopenharmony_ci rdata->mr = NULL; 36118c2ecf20Sopenharmony_ci } 36128c2ecf20Sopenharmony_ci#endif 36138c2ecf20Sopenharmony_ci rc = server->ops->async_readv(rdata); 36148c2ecf20Sopenharmony_ci } 36158c2ecf20Sopenharmony_ci } 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci /* If the read was successfully sent, we are done */ 36188c2ecf20Sopenharmony_ci if (!rc) { 36198c2ecf20Sopenharmony_ci /* Add to aio pending list */ 36208c2ecf20Sopenharmony_ci list_add_tail(&rdata->list, rdata_list); 36218c2ecf20Sopenharmony_ci return 0; 36228c2ecf20Sopenharmony_ci } 36238c2ecf20Sopenharmony_ci 36248c2ecf20Sopenharmony_ci /* Roll back credits and retry if needed */ 36258c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, &rdata->credits, 0); 36268c2ecf20Sopenharmony_ci } while (rc == -EAGAIN); 36278c2ecf20Sopenharmony_ci 36288c2ecf20Sopenharmony_cifail: 36298c2ecf20Sopenharmony_ci kref_put(&rdata->refcount, cifs_uncached_readdata_release); 36308c2ecf20Sopenharmony_ci return rc; 36318c2ecf20Sopenharmony_ci} 36328c2ecf20Sopenharmony_ci 36338c2ecf20Sopenharmony_cistatic int 36348c2ecf20Sopenharmony_cicifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, 36358c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb, struct list_head *rdata_list, 36368c2ecf20Sopenharmony_ci struct cifs_aio_ctx *ctx) 36378c2ecf20Sopenharmony_ci{ 36388c2ecf20Sopenharmony_ci struct cifs_readdata *rdata; 36398c2ecf20Sopenharmony_ci unsigned int npages, rsize; 36408c2ecf20Sopenharmony_ci struct cifs_credits credits_on_stack; 36418c2ecf20Sopenharmony_ci struct cifs_credits *credits = &credits_on_stack; 36428c2ecf20Sopenharmony_ci size_t cur_len; 36438c2ecf20Sopenharmony_ci int rc; 36448c2ecf20Sopenharmony_ci pid_t pid; 36458c2ecf20Sopenharmony_ci struct TCP_Server_Info *server; 36468c2ecf20Sopenharmony_ci struct page **pagevec; 36478c2ecf20Sopenharmony_ci size_t start; 36488c2ecf20Sopenharmony_ci struct iov_iter direct_iov = ctx->iter; 36498c2ecf20Sopenharmony_ci 36508c2ecf20Sopenharmony_ci server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses); 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) 36538c2ecf20Sopenharmony_ci pid = open_file->pid; 36548c2ecf20Sopenharmony_ci else 36558c2ecf20Sopenharmony_ci pid = current->tgid; 36568c2ecf20Sopenharmony_ci 36578c2ecf20Sopenharmony_ci if (ctx->direct_io) 36588c2ecf20Sopenharmony_ci iov_iter_advance(&direct_iov, offset - ctx->pos); 36598c2ecf20Sopenharmony_ci 36608c2ecf20Sopenharmony_ci do { 36618c2ecf20Sopenharmony_ci if (open_file->invalidHandle) { 36628c2ecf20Sopenharmony_ci rc = cifs_reopen_file(open_file, true); 36638c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 36648c2ecf20Sopenharmony_ci continue; 36658c2ecf20Sopenharmony_ci else if (rc) 36668c2ecf20Sopenharmony_ci break; 36678c2ecf20Sopenharmony_ci } 36688c2ecf20Sopenharmony_ci 36698c2ecf20Sopenharmony_ci rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize, 36708c2ecf20Sopenharmony_ci &rsize, credits); 36718c2ecf20Sopenharmony_ci if (rc) 36728c2ecf20Sopenharmony_ci break; 36738c2ecf20Sopenharmony_ci 36748c2ecf20Sopenharmony_ci cur_len = min_t(const size_t, len, rsize); 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci if (ctx->direct_io) { 36778c2ecf20Sopenharmony_ci ssize_t result; 36788c2ecf20Sopenharmony_ci 36798c2ecf20Sopenharmony_ci result = iov_iter_get_pages_alloc( 36808c2ecf20Sopenharmony_ci &direct_iov, &pagevec, 36818c2ecf20Sopenharmony_ci cur_len, &start); 36828c2ecf20Sopenharmony_ci if (result < 0) { 36838c2ecf20Sopenharmony_ci cifs_dbg(VFS, 36848c2ecf20Sopenharmony_ci "Couldn't get user pages (rc=%zd) iter type %d iov_offset %zd count %zd\n", 36858c2ecf20Sopenharmony_ci result, iov_iter_type(&direct_iov), 36868c2ecf20Sopenharmony_ci direct_iov.iov_offset, 36878c2ecf20Sopenharmony_ci direct_iov.count); 36888c2ecf20Sopenharmony_ci dump_stack(); 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci rc = result; 36918c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 36928c2ecf20Sopenharmony_ci break; 36938c2ecf20Sopenharmony_ci } 36948c2ecf20Sopenharmony_ci cur_len = (size_t)result; 36958c2ecf20Sopenharmony_ci iov_iter_advance(&direct_iov, cur_len); 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_ci rdata = cifs_readdata_direct_alloc( 36988c2ecf20Sopenharmony_ci pagevec, cifs_uncached_readv_complete); 36998c2ecf20Sopenharmony_ci if (!rdata) { 37008c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 37018c2ecf20Sopenharmony_ci rc = -ENOMEM; 37028c2ecf20Sopenharmony_ci break; 37038c2ecf20Sopenharmony_ci } 37048c2ecf20Sopenharmony_ci 37058c2ecf20Sopenharmony_ci npages = (cur_len + start + PAGE_SIZE-1) / PAGE_SIZE; 37068c2ecf20Sopenharmony_ci rdata->page_offset = start; 37078c2ecf20Sopenharmony_ci rdata->tailsz = npages > 1 ? 37088c2ecf20Sopenharmony_ci cur_len-(PAGE_SIZE-start)-(npages-2)*PAGE_SIZE : 37098c2ecf20Sopenharmony_ci cur_len; 37108c2ecf20Sopenharmony_ci 37118c2ecf20Sopenharmony_ci } else { 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci npages = DIV_ROUND_UP(cur_len, PAGE_SIZE); 37148c2ecf20Sopenharmony_ci /* allocate a readdata struct */ 37158c2ecf20Sopenharmony_ci rdata = cifs_readdata_alloc(npages, 37168c2ecf20Sopenharmony_ci cifs_uncached_readv_complete); 37178c2ecf20Sopenharmony_ci if (!rdata) { 37188c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 37198c2ecf20Sopenharmony_ci rc = -ENOMEM; 37208c2ecf20Sopenharmony_ci break; 37218c2ecf20Sopenharmony_ci } 37228c2ecf20Sopenharmony_ci 37238c2ecf20Sopenharmony_ci rc = cifs_read_allocate_pages(rdata, npages); 37248c2ecf20Sopenharmony_ci if (rc) { 37258c2ecf20Sopenharmony_ci kvfree(rdata->pages); 37268c2ecf20Sopenharmony_ci kfree(rdata); 37278c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 37288c2ecf20Sopenharmony_ci break; 37298c2ecf20Sopenharmony_ci } 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_ci rdata->tailsz = PAGE_SIZE; 37328c2ecf20Sopenharmony_ci } 37338c2ecf20Sopenharmony_ci 37348c2ecf20Sopenharmony_ci rdata->server = server; 37358c2ecf20Sopenharmony_ci rdata->cfile = cifsFileInfo_get(open_file); 37368c2ecf20Sopenharmony_ci rdata->nr_pages = npages; 37378c2ecf20Sopenharmony_ci rdata->offset = offset; 37388c2ecf20Sopenharmony_ci rdata->bytes = cur_len; 37398c2ecf20Sopenharmony_ci rdata->pid = pid; 37408c2ecf20Sopenharmony_ci rdata->pagesz = PAGE_SIZE; 37418c2ecf20Sopenharmony_ci rdata->read_into_pages = cifs_uncached_read_into_pages; 37428c2ecf20Sopenharmony_ci rdata->copy_into_pages = cifs_uncached_copy_into_pages; 37438c2ecf20Sopenharmony_ci rdata->credits = credits_on_stack; 37448c2ecf20Sopenharmony_ci rdata->ctx = ctx; 37458c2ecf20Sopenharmony_ci kref_get(&ctx->refcount); 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_ci rc = adjust_credits(server, &rdata->credits, rdata->bytes); 37488c2ecf20Sopenharmony_ci 37498c2ecf20Sopenharmony_ci if (!rc) { 37508c2ecf20Sopenharmony_ci if (rdata->cfile->invalidHandle) 37518c2ecf20Sopenharmony_ci rc = -EAGAIN; 37528c2ecf20Sopenharmony_ci else 37538c2ecf20Sopenharmony_ci rc = server->ops->async_readv(rdata); 37548c2ecf20Sopenharmony_ci } 37558c2ecf20Sopenharmony_ci 37568c2ecf20Sopenharmony_ci if (rc) { 37578c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, &rdata->credits, 0); 37588c2ecf20Sopenharmony_ci kref_put(&rdata->refcount, 37598c2ecf20Sopenharmony_ci cifs_uncached_readdata_release); 37608c2ecf20Sopenharmony_ci if (rc == -EAGAIN) { 37618c2ecf20Sopenharmony_ci iov_iter_revert(&direct_iov, cur_len); 37628c2ecf20Sopenharmony_ci continue; 37638c2ecf20Sopenharmony_ci } 37648c2ecf20Sopenharmony_ci break; 37658c2ecf20Sopenharmony_ci } 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_ci list_add_tail(&rdata->list, rdata_list); 37688c2ecf20Sopenharmony_ci offset += cur_len; 37698c2ecf20Sopenharmony_ci len -= cur_len; 37708c2ecf20Sopenharmony_ci } while (len > 0); 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci return rc; 37738c2ecf20Sopenharmony_ci} 37748c2ecf20Sopenharmony_ci 37758c2ecf20Sopenharmony_cistatic void 37768c2ecf20Sopenharmony_cicollect_uncached_read_data(struct cifs_aio_ctx *ctx) 37778c2ecf20Sopenharmony_ci{ 37788c2ecf20Sopenharmony_ci struct cifs_readdata *rdata, *tmp; 37798c2ecf20Sopenharmony_ci struct iov_iter *to = &ctx->iter; 37808c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb; 37818c2ecf20Sopenharmony_ci int rc; 37828c2ecf20Sopenharmony_ci 37838c2ecf20Sopenharmony_ci cifs_sb = CIFS_SB(ctx->cfile->dentry->d_sb); 37848c2ecf20Sopenharmony_ci 37858c2ecf20Sopenharmony_ci mutex_lock(&ctx->aio_mutex); 37868c2ecf20Sopenharmony_ci 37878c2ecf20Sopenharmony_ci if (list_empty(&ctx->list)) { 37888c2ecf20Sopenharmony_ci mutex_unlock(&ctx->aio_mutex); 37898c2ecf20Sopenharmony_ci return; 37908c2ecf20Sopenharmony_ci } 37918c2ecf20Sopenharmony_ci 37928c2ecf20Sopenharmony_ci rc = ctx->rc; 37938c2ecf20Sopenharmony_ci /* the loop below should proceed in the order of increasing offsets */ 37948c2ecf20Sopenharmony_ciagain: 37958c2ecf20Sopenharmony_ci list_for_each_entry_safe(rdata, tmp, &ctx->list, list) { 37968c2ecf20Sopenharmony_ci if (!rc) { 37978c2ecf20Sopenharmony_ci if (!try_wait_for_completion(&rdata->done)) { 37988c2ecf20Sopenharmony_ci mutex_unlock(&ctx->aio_mutex); 37998c2ecf20Sopenharmony_ci return; 38008c2ecf20Sopenharmony_ci } 38018c2ecf20Sopenharmony_ci 38028c2ecf20Sopenharmony_ci if (rdata->result == -EAGAIN) { 38038c2ecf20Sopenharmony_ci /* resend call if it's a retryable error */ 38048c2ecf20Sopenharmony_ci struct list_head tmp_list; 38058c2ecf20Sopenharmony_ci unsigned int got_bytes = rdata->got_bytes; 38068c2ecf20Sopenharmony_ci 38078c2ecf20Sopenharmony_ci list_del_init(&rdata->list); 38088c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tmp_list); 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci /* 38118c2ecf20Sopenharmony_ci * Got a part of data and then reconnect has 38128c2ecf20Sopenharmony_ci * happened -- fill the buffer and continue 38138c2ecf20Sopenharmony_ci * reading. 38148c2ecf20Sopenharmony_ci */ 38158c2ecf20Sopenharmony_ci if (got_bytes && got_bytes < rdata->bytes) { 38168c2ecf20Sopenharmony_ci rc = 0; 38178c2ecf20Sopenharmony_ci if (!ctx->direct_io) 38188c2ecf20Sopenharmony_ci rc = cifs_readdata_to_iov(rdata, to); 38198c2ecf20Sopenharmony_ci if (rc) { 38208c2ecf20Sopenharmony_ci kref_put(&rdata->refcount, 38218c2ecf20Sopenharmony_ci cifs_uncached_readdata_release); 38228c2ecf20Sopenharmony_ci continue; 38238c2ecf20Sopenharmony_ci } 38248c2ecf20Sopenharmony_ci } 38258c2ecf20Sopenharmony_ci 38268c2ecf20Sopenharmony_ci if (ctx->direct_io) { 38278c2ecf20Sopenharmony_ci /* 38288c2ecf20Sopenharmony_ci * Re-use rdata as this is a 38298c2ecf20Sopenharmony_ci * direct I/O 38308c2ecf20Sopenharmony_ci */ 38318c2ecf20Sopenharmony_ci rc = cifs_resend_rdata( 38328c2ecf20Sopenharmony_ci rdata, 38338c2ecf20Sopenharmony_ci &tmp_list, ctx); 38348c2ecf20Sopenharmony_ci } else { 38358c2ecf20Sopenharmony_ci rc = cifs_send_async_read( 38368c2ecf20Sopenharmony_ci rdata->offset + got_bytes, 38378c2ecf20Sopenharmony_ci rdata->bytes - got_bytes, 38388c2ecf20Sopenharmony_ci rdata->cfile, cifs_sb, 38398c2ecf20Sopenharmony_ci &tmp_list, ctx); 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci kref_put(&rdata->refcount, 38428c2ecf20Sopenharmony_ci cifs_uncached_readdata_release); 38438c2ecf20Sopenharmony_ci } 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_ci list_splice(&tmp_list, &ctx->list); 38468c2ecf20Sopenharmony_ci 38478c2ecf20Sopenharmony_ci goto again; 38488c2ecf20Sopenharmony_ci } else if (rdata->result) 38498c2ecf20Sopenharmony_ci rc = rdata->result; 38508c2ecf20Sopenharmony_ci else if (!ctx->direct_io) 38518c2ecf20Sopenharmony_ci rc = cifs_readdata_to_iov(rdata, to); 38528c2ecf20Sopenharmony_ci 38538c2ecf20Sopenharmony_ci /* if there was a short read -- discard anything left */ 38548c2ecf20Sopenharmony_ci if (rdata->got_bytes && rdata->got_bytes < rdata->bytes) 38558c2ecf20Sopenharmony_ci rc = -ENODATA; 38568c2ecf20Sopenharmony_ci 38578c2ecf20Sopenharmony_ci ctx->total_len += rdata->got_bytes; 38588c2ecf20Sopenharmony_ci } 38598c2ecf20Sopenharmony_ci list_del_init(&rdata->list); 38608c2ecf20Sopenharmony_ci kref_put(&rdata->refcount, cifs_uncached_readdata_release); 38618c2ecf20Sopenharmony_ci } 38628c2ecf20Sopenharmony_ci 38638c2ecf20Sopenharmony_ci if (!ctx->direct_io) 38648c2ecf20Sopenharmony_ci ctx->total_len = ctx->len - iov_iter_count(to); 38658c2ecf20Sopenharmony_ci 38668c2ecf20Sopenharmony_ci /* mask nodata case */ 38678c2ecf20Sopenharmony_ci if (rc == -ENODATA) 38688c2ecf20Sopenharmony_ci rc = 0; 38698c2ecf20Sopenharmony_ci 38708c2ecf20Sopenharmony_ci ctx->rc = (rc == 0) ? (ssize_t)ctx->total_len : rc; 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_ci mutex_unlock(&ctx->aio_mutex); 38738c2ecf20Sopenharmony_ci 38748c2ecf20Sopenharmony_ci if (ctx->iocb && ctx->iocb->ki_complete) 38758c2ecf20Sopenharmony_ci ctx->iocb->ki_complete(ctx->iocb, ctx->rc, 0); 38768c2ecf20Sopenharmony_ci else 38778c2ecf20Sopenharmony_ci complete(&ctx->done); 38788c2ecf20Sopenharmony_ci} 38798c2ecf20Sopenharmony_ci 38808c2ecf20Sopenharmony_cistatic ssize_t __cifs_readv( 38818c2ecf20Sopenharmony_ci struct kiocb *iocb, struct iov_iter *to, bool direct) 38828c2ecf20Sopenharmony_ci{ 38838c2ecf20Sopenharmony_ci size_t len; 38848c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 38858c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb; 38868c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile; 38878c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 38888c2ecf20Sopenharmony_ci ssize_t rc, total_read = 0; 38898c2ecf20Sopenharmony_ci loff_t offset = iocb->ki_pos; 38908c2ecf20Sopenharmony_ci struct cifs_aio_ctx *ctx; 38918c2ecf20Sopenharmony_ci 38928c2ecf20Sopenharmony_ci /* 38938c2ecf20Sopenharmony_ci * iov_iter_get_pages_alloc() doesn't work with ITER_KVEC, 38948c2ecf20Sopenharmony_ci * fall back to data copy read path 38958c2ecf20Sopenharmony_ci * this could be improved by getting pages directly in ITER_KVEC 38968c2ecf20Sopenharmony_ci */ 38978c2ecf20Sopenharmony_ci if (direct && iov_iter_is_kvec(to)) { 38988c2ecf20Sopenharmony_ci cifs_dbg(FYI, "use non-direct cifs_user_readv for kvec I/O\n"); 38998c2ecf20Sopenharmony_ci direct = false; 39008c2ecf20Sopenharmony_ci } 39018c2ecf20Sopenharmony_ci 39028c2ecf20Sopenharmony_ci len = iov_iter_count(to); 39038c2ecf20Sopenharmony_ci if (!len) 39048c2ecf20Sopenharmony_ci return 0; 39058c2ecf20Sopenharmony_ci 39068c2ecf20Sopenharmony_ci cifs_sb = CIFS_FILE_SB(file); 39078c2ecf20Sopenharmony_ci cfile = file->private_data; 39088c2ecf20Sopenharmony_ci tcon = tlink_tcon(cfile->tlink); 39098c2ecf20Sopenharmony_ci 39108c2ecf20Sopenharmony_ci if (!tcon->ses->server->ops->async_readv) 39118c2ecf20Sopenharmony_ci return -ENOSYS; 39128c2ecf20Sopenharmony_ci 39138c2ecf20Sopenharmony_ci if ((file->f_flags & O_ACCMODE) == O_WRONLY) 39148c2ecf20Sopenharmony_ci cifs_dbg(FYI, "attempting read on write only file instance\n"); 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_ci ctx = cifs_aio_ctx_alloc(); 39178c2ecf20Sopenharmony_ci if (!ctx) 39188c2ecf20Sopenharmony_ci return -ENOMEM; 39198c2ecf20Sopenharmony_ci 39208c2ecf20Sopenharmony_ci ctx->cfile = cifsFileInfo_get(cfile); 39218c2ecf20Sopenharmony_ci 39228c2ecf20Sopenharmony_ci if (!is_sync_kiocb(iocb)) 39238c2ecf20Sopenharmony_ci ctx->iocb = iocb; 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_ci if (iter_is_iovec(to)) 39268c2ecf20Sopenharmony_ci ctx->should_dirty = true; 39278c2ecf20Sopenharmony_ci 39288c2ecf20Sopenharmony_ci if (direct) { 39298c2ecf20Sopenharmony_ci ctx->pos = offset; 39308c2ecf20Sopenharmony_ci ctx->direct_io = true; 39318c2ecf20Sopenharmony_ci ctx->iter = *to; 39328c2ecf20Sopenharmony_ci ctx->len = len; 39338c2ecf20Sopenharmony_ci } else { 39348c2ecf20Sopenharmony_ci rc = setup_aio_ctx_iter(ctx, to, READ); 39358c2ecf20Sopenharmony_ci if (rc) { 39368c2ecf20Sopenharmony_ci kref_put(&ctx->refcount, cifs_aio_ctx_release); 39378c2ecf20Sopenharmony_ci return rc; 39388c2ecf20Sopenharmony_ci } 39398c2ecf20Sopenharmony_ci len = ctx->len; 39408c2ecf20Sopenharmony_ci } 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci if (direct) { 39438c2ecf20Sopenharmony_ci rc = filemap_write_and_wait_range(file->f_inode->i_mapping, 39448c2ecf20Sopenharmony_ci offset, offset + len - 1); 39458c2ecf20Sopenharmony_ci if (rc) { 39468c2ecf20Sopenharmony_ci kref_put(&ctx->refcount, cifs_aio_ctx_release); 39478c2ecf20Sopenharmony_ci return -EAGAIN; 39488c2ecf20Sopenharmony_ci } 39498c2ecf20Sopenharmony_ci } 39508c2ecf20Sopenharmony_ci 39518c2ecf20Sopenharmony_ci /* grab a lock here due to read response handlers can access ctx */ 39528c2ecf20Sopenharmony_ci mutex_lock(&ctx->aio_mutex); 39538c2ecf20Sopenharmony_ci 39548c2ecf20Sopenharmony_ci rc = cifs_send_async_read(offset, len, cfile, cifs_sb, &ctx->list, ctx); 39558c2ecf20Sopenharmony_ci 39568c2ecf20Sopenharmony_ci /* if at least one read request send succeeded, then reset rc */ 39578c2ecf20Sopenharmony_ci if (!list_empty(&ctx->list)) 39588c2ecf20Sopenharmony_ci rc = 0; 39598c2ecf20Sopenharmony_ci 39608c2ecf20Sopenharmony_ci mutex_unlock(&ctx->aio_mutex); 39618c2ecf20Sopenharmony_ci 39628c2ecf20Sopenharmony_ci if (rc) { 39638c2ecf20Sopenharmony_ci kref_put(&ctx->refcount, cifs_aio_ctx_release); 39648c2ecf20Sopenharmony_ci return rc; 39658c2ecf20Sopenharmony_ci } 39668c2ecf20Sopenharmony_ci 39678c2ecf20Sopenharmony_ci if (!is_sync_kiocb(iocb)) { 39688c2ecf20Sopenharmony_ci kref_put(&ctx->refcount, cifs_aio_ctx_release); 39698c2ecf20Sopenharmony_ci return -EIOCBQUEUED; 39708c2ecf20Sopenharmony_ci } 39718c2ecf20Sopenharmony_ci 39728c2ecf20Sopenharmony_ci rc = wait_for_completion_killable(&ctx->done); 39738c2ecf20Sopenharmony_ci if (rc) { 39748c2ecf20Sopenharmony_ci mutex_lock(&ctx->aio_mutex); 39758c2ecf20Sopenharmony_ci ctx->rc = rc = -EINTR; 39768c2ecf20Sopenharmony_ci total_read = ctx->total_len; 39778c2ecf20Sopenharmony_ci mutex_unlock(&ctx->aio_mutex); 39788c2ecf20Sopenharmony_ci } else { 39798c2ecf20Sopenharmony_ci rc = ctx->rc; 39808c2ecf20Sopenharmony_ci total_read = ctx->total_len; 39818c2ecf20Sopenharmony_ci } 39828c2ecf20Sopenharmony_ci 39838c2ecf20Sopenharmony_ci kref_put(&ctx->refcount, cifs_aio_ctx_release); 39848c2ecf20Sopenharmony_ci 39858c2ecf20Sopenharmony_ci if (total_read) { 39868c2ecf20Sopenharmony_ci iocb->ki_pos += total_read; 39878c2ecf20Sopenharmony_ci return total_read; 39888c2ecf20Sopenharmony_ci } 39898c2ecf20Sopenharmony_ci return rc; 39908c2ecf20Sopenharmony_ci} 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_cissize_t cifs_direct_readv(struct kiocb *iocb, struct iov_iter *to) 39938c2ecf20Sopenharmony_ci{ 39948c2ecf20Sopenharmony_ci return __cifs_readv(iocb, to, true); 39958c2ecf20Sopenharmony_ci} 39968c2ecf20Sopenharmony_ci 39978c2ecf20Sopenharmony_cissize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to) 39988c2ecf20Sopenharmony_ci{ 39998c2ecf20Sopenharmony_ci return __cifs_readv(iocb, to, false); 40008c2ecf20Sopenharmony_ci} 40018c2ecf20Sopenharmony_ci 40028c2ecf20Sopenharmony_cissize_t 40038c2ecf20Sopenharmony_cicifs_strict_readv(struct kiocb *iocb, struct iov_iter *to) 40048c2ecf20Sopenharmony_ci{ 40058c2ecf20Sopenharmony_ci struct inode *inode = file_inode(iocb->ki_filp); 40068c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(inode); 40078c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 40088c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile = (struct cifsFileInfo *) 40098c2ecf20Sopenharmony_ci iocb->ki_filp->private_data; 40108c2ecf20Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 40118c2ecf20Sopenharmony_ci int rc = -EACCES; 40128c2ecf20Sopenharmony_ci 40138c2ecf20Sopenharmony_ci /* 40148c2ecf20Sopenharmony_ci * In strict cache mode we need to read from the server all the time 40158c2ecf20Sopenharmony_ci * if we don't have level II oplock because the server can delay mtime 40168c2ecf20Sopenharmony_ci * change - so we can't make a decision about inode invalidating. 40178c2ecf20Sopenharmony_ci * And we can also fail with pagereading if there are mandatory locks 40188c2ecf20Sopenharmony_ci * on pages affected by this read but not on the region from pos to 40198c2ecf20Sopenharmony_ci * pos+len-1. 40208c2ecf20Sopenharmony_ci */ 40218c2ecf20Sopenharmony_ci if (!CIFS_CACHE_READ(cinode)) 40228c2ecf20Sopenharmony_ci return cifs_user_readv(iocb, to); 40238c2ecf20Sopenharmony_ci 40248c2ecf20Sopenharmony_ci if (cap_unix(tcon->ses) && 40258c2ecf20Sopenharmony_ci (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && 40268c2ecf20Sopenharmony_ci ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0)) 40278c2ecf20Sopenharmony_ci return generic_file_read_iter(iocb, to); 40288c2ecf20Sopenharmony_ci 40298c2ecf20Sopenharmony_ci /* 40308c2ecf20Sopenharmony_ci * We need to hold the sem to be sure nobody modifies lock list 40318c2ecf20Sopenharmony_ci * with a brlock that prevents reading. 40328c2ecf20Sopenharmony_ci */ 40338c2ecf20Sopenharmony_ci down_read(&cinode->lock_sem); 40348c2ecf20Sopenharmony_ci if (!cifs_find_lock_conflict(cfile, iocb->ki_pos, iov_iter_count(to), 40358c2ecf20Sopenharmony_ci tcon->ses->server->vals->shared_lock_type, 40368c2ecf20Sopenharmony_ci 0, NULL, CIFS_READ_OP)) 40378c2ecf20Sopenharmony_ci rc = generic_file_read_iter(iocb, to); 40388c2ecf20Sopenharmony_ci up_read(&cinode->lock_sem); 40398c2ecf20Sopenharmony_ci return rc; 40408c2ecf20Sopenharmony_ci} 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_cistatic ssize_t 40438c2ecf20Sopenharmony_cicifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset) 40448c2ecf20Sopenharmony_ci{ 40458c2ecf20Sopenharmony_ci int rc = -EACCES; 40468c2ecf20Sopenharmony_ci unsigned int bytes_read = 0; 40478c2ecf20Sopenharmony_ci unsigned int total_read; 40488c2ecf20Sopenharmony_ci unsigned int current_read_size; 40498c2ecf20Sopenharmony_ci unsigned int rsize; 40508c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb; 40518c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 40528c2ecf20Sopenharmony_ci struct TCP_Server_Info *server; 40538c2ecf20Sopenharmony_ci unsigned int xid; 40548c2ecf20Sopenharmony_ci char *cur_offset; 40558c2ecf20Sopenharmony_ci struct cifsFileInfo *open_file; 40568c2ecf20Sopenharmony_ci struct cifs_io_parms io_parms = {0}; 40578c2ecf20Sopenharmony_ci int buf_type = CIFS_NO_BUFFER; 40588c2ecf20Sopenharmony_ci __u32 pid; 40598c2ecf20Sopenharmony_ci 40608c2ecf20Sopenharmony_ci xid = get_xid(); 40618c2ecf20Sopenharmony_ci cifs_sb = CIFS_FILE_SB(file); 40628c2ecf20Sopenharmony_ci 40638c2ecf20Sopenharmony_ci /* FIXME: set up handlers for larger reads and/or convert to async */ 40648c2ecf20Sopenharmony_ci rsize = min_t(unsigned int, cifs_sb->rsize, CIFSMaxBufSize); 40658c2ecf20Sopenharmony_ci 40668c2ecf20Sopenharmony_ci if (file->private_data == NULL) { 40678c2ecf20Sopenharmony_ci rc = -EBADF; 40688c2ecf20Sopenharmony_ci free_xid(xid); 40698c2ecf20Sopenharmony_ci return rc; 40708c2ecf20Sopenharmony_ci } 40718c2ecf20Sopenharmony_ci open_file = file->private_data; 40728c2ecf20Sopenharmony_ci tcon = tlink_tcon(open_file->tlink); 40738c2ecf20Sopenharmony_ci server = cifs_pick_channel(tcon->ses); 40748c2ecf20Sopenharmony_ci 40758c2ecf20Sopenharmony_ci if (!server->ops->sync_read) { 40768c2ecf20Sopenharmony_ci free_xid(xid); 40778c2ecf20Sopenharmony_ci return -ENOSYS; 40788c2ecf20Sopenharmony_ci } 40798c2ecf20Sopenharmony_ci 40808c2ecf20Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) 40818c2ecf20Sopenharmony_ci pid = open_file->pid; 40828c2ecf20Sopenharmony_ci else 40838c2ecf20Sopenharmony_ci pid = current->tgid; 40848c2ecf20Sopenharmony_ci 40858c2ecf20Sopenharmony_ci if ((file->f_flags & O_ACCMODE) == O_WRONLY) 40868c2ecf20Sopenharmony_ci cifs_dbg(FYI, "attempting read on write only file instance\n"); 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci for (total_read = 0, cur_offset = read_data; read_size > total_read; 40898c2ecf20Sopenharmony_ci total_read += bytes_read, cur_offset += bytes_read) { 40908c2ecf20Sopenharmony_ci do { 40918c2ecf20Sopenharmony_ci current_read_size = min_t(uint, read_size - total_read, 40928c2ecf20Sopenharmony_ci rsize); 40938c2ecf20Sopenharmony_ci /* 40948c2ecf20Sopenharmony_ci * For windows me and 9x we do not want to request more 40958c2ecf20Sopenharmony_ci * than it negotiated since it will refuse the read 40968c2ecf20Sopenharmony_ci * then. 40978c2ecf20Sopenharmony_ci */ 40988c2ecf20Sopenharmony_ci if (!(tcon->ses->capabilities & 40998c2ecf20Sopenharmony_ci tcon->ses->server->vals->cap_large_files)) { 41008c2ecf20Sopenharmony_ci current_read_size = min_t(uint, 41018c2ecf20Sopenharmony_ci current_read_size, CIFSMaxBufSize); 41028c2ecf20Sopenharmony_ci } 41038c2ecf20Sopenharmony_ci if (open_file->invalidHandle) { 41048c2ecf20Sopenharmony_ci rc = cifs_reopen_file(open_file, true); 41058c2ecf20Sopenharmony_ci if (rc != 0) 41068c2ecf20Sopenharmony_ci break; 41078c2ecf20Sopenharmony_ci } 41088c2ecf20Sopenharmony_ci io_parms.pid = pid; 41098c2ecf20Sopenharmony_ci io_parms.tcon = tcon; 41108c2ecf20Sopenharmony_ci io_parms.offset = *offset; 41118c2ecf20Sopenharmony_ci io_parms.length = current_read_size; 41128c2ecf20Sopenharmony_ci io_parms.server = server; 41138c2ecf20Sopenharmony_ci rc = server->ops->sync_read(xid, &open_file->fid, &io_parms, 41148c2ecf20Sopenharmony_ci &bytes_read, &cur_offset, 41158c2ecf20Sopenharmony_ci &buf_type); 41168c2ecf20Sopenharmony_ci } while (rc == -EAGAIN); 41178c2ecf20Sopenharmony_ci 41188c2ecf20Sopenharmony_ci if (rc || (bytes_read == 0)) { 41198c2ecf20Sopenharmony_ci if (total_read) { 41208c2ecf20Sopenharmony_ci break; 41218c2ecf20Sopenharmony_ci } else { 41228c2ecf20Sopenharmony_ci free_xid(xid); 41238c2ecf20Sopenharmony_ci return rc; 41248c2ecf20Sopenharmony_ci } 41258c2ecf20Sopenharmony_ci } else { 41268c2ecf20Sopenharmony_ci cifs_stats_bytes_read(tcon, total_read); 41278c2ecf20Sopenharmony_ci *offset += bytes_read; 41288c2ecf20Sopenharmony_ci } 41298c2ecf20Sopenharmony_ci } 41308c2ecf20Sopenharmony_ci free_xid(xid); 41318c2ecf20Sopenharmony_ci return total_read; 41328c2ecf20Sopenharmony_ci} 41338c2ecf20Sopenharmony_ci 41348c2ecf20Sopenharmony_ci/* 41358c2ecf20Sopenharmony_ci * If the page is mmap'ed into a process' page tables, then we need to make 41368c2ecf20Sopenharmony_ci * sure that it doesn't change while being written back. 41378c2ecf20Sopenharmony_ci */ 41388c2ecf20Sopenharmony_cistatic vm_fault_t 41398c2ecf20Sopenharmony_cicifs_page_mkwrite(struct vm_fault *vmf) 41408c2ecf20Sopenharmony_ci{ 41418c2ecf20Sopenharmony_ci struct page *page = vmf->page; 41428c2ecf20Sopenharmony_ci 41438c2ecf20Sopenharmony_ci lock_page(page); 41448c2ecf20Sopenharmony_ci return VM_FAULT_LOCKED; 41458c2ecf20Sopenharmony_ci} 41468c2ecf20Sopenharmony_ci 41478c2ecf20Sopenharmony_cistatic const struct vm_operations_struct cifs_file_vm_ops = { 41488c2ecf20Sopenharmony_ci .fault = filemap_fault, 41498c2ecf20Sopenharmony_ci .map_pages = filemap_map_pages, 41508c2ecf20Sopenharmony_ci .page_mkwrite = cifs_page_mkwrite, 41518c2ecf20Sopenharmony_ci}; 41528c2ecf20Sopenharmony_ci 41538c2ecf20Sopenharmony_ciint cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) 41548c2ecf20Sopenharmony_ci{ 41558c2ecf20Sopenharmony_ci int xid, rc = 0; 41568c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 41578c2ecf20Sopenharmony_ci 41588c2ecf20Sopenharmony_ci xid = get_xid(); 41598c2ecf20Sopenharmony_ci 41608c2ecf20Sopenharmony_ci if (!CIFS_CACHE_READ(CIFS_I(inode))) 41618c2ecf20Sopenharmony_ci rc = cifs_zap_mapping(inode); 41628c2ecf20Sopenharmony_ci if (!rc) 41638c2ecf20Sopenharmony_ci rc = generic_file_mmap(file, vma); 41648c2ecf20Sopenharmony_ci if (!rc) 41658c2ecf20Sopenharmony_ci vma->vm_ops = &cifs_file_vm_ops; 41668c2ecf20Sopenharmony_ci 41678c2ecf20Sopenharmony_ci free_xid(xid); 41688c2ecf20Sopenharmony_ci return rc; 41698c2ecf20Sopenharmony_ci} 41708c2ecf20Sopenharmony_ci 41718c2ecf20Sopenharmony_ciint cifs_file_mmap(struct file *file, struct vm_area_struct *vma) 41728c2ecf20Sopenharmony_ci{ 41738c2ecf20Sopenharmony_ci int rc, xid; 41748c2ecf20Sopenharmony_ci 41758c2ecf20Sopenharmony_ci xid = get_xid(); 41768c2ecf20Sopenharmony_ci 41778c2ecf20Sopenharmony_ci rc = cifs_revalidate_file(file); 41788c2ecf20Sopenharmony_ci if (rc) 41798c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Validation prior to mmap failed, error=%d\n", 41808c2ecf20Sopenharmony_ci rc); 41818c2ecf20Sopenharmony_ci if (!rc) 41828c2ecf20Sopenharmony_ci rc = generic_file_mmap(file, vma); 41838c2ecf20Sopenharmony_ci if (!rc) 41848c2ecf20Sopenharmony_ci vma->vm_ops = &cifs_file_vm_ops; 41858c2ecf20Sopenharmony_ci 41868c2ecf20Sopenharmony_ci free_xid(xid); 41878c2ecf20Sopenharmony_ci return rc; 41888c2ecf20Sopenharmony_ci} 41898c2ecf20Sopenharmony_ci 41908c2ecf20Sopenharmony_cistatic void 41918c2ecf20Sopenharmony_cicifs_readv_complete(struct work_struct *work) 41928c2ecf20Sopenharmony_ci{ 41938c2ecf20Sopenharmony_ci unsigned int i, got_bytes; 41948c2ecf20Sopenharmony_ci struct cifs_readdata *rdata = container_of(work, 41958c2ecf20Sopenharmony_ci struct cifs_readdata, work); 41968c2ecf20Sopenharmony_ci 41978c2ecf20Sopenharmony_ci got_bytes = rdata->got_bytes; 41988c2ecf20Sopenharmony_ci for (i = 0; i < rdata->nr_pages; i++) { 41998c2ecf20Sopenharmony_ci struct page *page = rdata->pages[i]; 42008c2ecf20Sopenharmony_ci 42018c2ecf20Sopenharmony_ci lru_cache_add(page); 42028c2ecf20Sopenharmony_ci 42038c2ecf20Sopenharmony_ci if (rdata->result == 0 || 42048c2ecf20Sopenharmony_ci (rdata->result == -EAGAIN && got_bytes)) { 42058c2ecf20Sopenharmony_ci flush_dcache_page(page); 42068c2ecf20Sopenharmony_ci SetPageUptodate(page); 42078c2ecf20Sopenharmony_ci } 42088c2ecf20Sopenharmony_ci 42098c2ecf20Sopenharmony_ci unlock_page(page); 42108c2ecf20Sopenharmony_ci 42118c2ecf20Sopenharmony_ci if (rdata->result == 0 || 42128c2ecf20Sopenharmony_ci (rdata->result == -EAGAIN && got_bytes)) 42138c2ecf20Sopenharmony_ci cifs_readpage_to_fscache(rdata->mapping->host, page); 42148c2ecf20Sopenharmony_ci 42158c2ecf20Sopenharmony_ci got_bytes -= min_t(unsigned int, PAGE_SIZE, got_bytes); 42168c2ecf20Sopenharmony_ci 42178c2ecf20Sopenharmony_ci put_page(page); 42188c2ecf20Sopenharmony_ci rdata->pages[i] = NULL; 42198c2ecf20Sopenharmony_ci } 42208c2ecf20Sopenharmony_ci kref_put(&rdata->refcount, cifs_readdata_release); 42218c2ecf20Sopenharmony_ci} 42228c2ecf20Sopenharmony_ci 42238c2ecf20Sopenharmony_cistatic int 42248c2ecf20Sopenharmony_cireadpages_fill_pages(struct TCP_Server_Info *server, 42258c2ecf20Sopenharmony_ci struct cifs_readdata *rdata, struct iov_iter *iter, 42268c2ecf20Sopenharmony_ci unsigned int len) 42278c2ecf20Sopenharmony_ci{ 42288c2ecf20Sopenharmony_ci int result = 0; 42298c2ecf20Sopenharmony_ci unsigned int i; 42308c2ecf20Sopenharmony_ci u64 eof; 42318c2ecf20Sopenharmony_ci pgoff_t eof_index; 42328c2ecf20Sopenharmony_ci unsigned int nr_pages = rdata->nr_pages; 42338c2ecf20Sopenharmony_ci unsigned int page_offset = rdata->page_offset; 42348c2ecf20Sopenharmony_ci 42358c2ecf20Sopenharmony_ci /* determine the eof that the server (probably) has */ 42368c2ecf20Sopenharmony_ci eof = CIFS_I(rdata->mapping->host)->server_eof; 42378c2ecf20Sopenharmony_ci eof_index = eof ? (eof - 1) >> PAGE_SHIFT : 0; 42388c2ecf20Sopenharmony_ci cifs_dbg(FYI, "eof=%llu eof_index=%lu\n", eof, eof_index); 42398c2ecf20Sopenharmony_ci 42408c2ecf20Sopenharmony_ci rdata->got_bytes = 0; 42418c2ecf20Sopenharmony_ci rdata->tailsz = PAGE_SIZE; 42428c2ecf20Sopenharmony_ci for (i = 0; i < nr_pages; i++) { 42438c2ecf20Sopenharmony_ci struct page *page = rdata->pages[i]; 42448c2ecf20Sopenharmony_ci unsigned int to_read = rdata->pagesz; 42458c2ecf20Sopenharmony_ci size_t n; 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci if (i == 0) 42488c2ecf20Sopenharmony_ci to_read -= page_offset; 42498c2ecf20Sopenharmony_ci else 42508c2ecf20Sopenharmony_ci page_offset = 0; 42518c2ecf20Sopenharmony_ci 42528c2ecf20Sopenharmony_ci n = to_read; 42538c2ecf20Sopenharmony_ci 42548c2ecf20Sopenharmony_ci if (len >= to_read) { 42558c2ecf20Sopenharmony_ci len -= to_read; 42568c2ecf20Sopenharmony_ci } else if (len > 0) { 42578c2ecf20Sopenharmony_ci /* enough for partial page, fill and zero the rest */ 42588c2ecf20Sopenharmony_ci zero_user(page, len + page_offset, to_read - len); 42598c2ecf20Sopenharmony_ci n = rdata->tailsz = len; 42608c2ecf20Sopenharmony_ci len = 0; 42618c2ecf20Sopenharmony_ci } else if (page->index > eof_index) { 42628c2ecf20Sopenharmony_ci /* 42638c2ecf20Sopenharmony_ci * The VFS will not try to do readahead past the 42648c2ecf20Sopenharmony_ci * i_size, but it's possible that we have outstanding 42658c2ecf20Sopenharmony_ci * writes with gaps in the middle and the i_size hasn't 42668c2ecf20Sopenharmony_ci * caught up yet. Populate those with zeroed out pages 42678c2ecf20Sopenharmony_ci * to prevent the VFS from repeatedly attempting to 42688c2ecf20Sopenharmony_ci * fill them until the writes are flushed. 42698c2ecf20Sopenharmony_ci */ 42708c2ecf20Sopenharmony_ci zero_user(page, 0, PAGE_SIZE); 42718c2ecf20Sopenharmony_ci lru_cache_add(page); 42728c2ecf20Sopenharmony_ci flush_dcache_page(page); 42738c2ecf20Sopenharmony_ci SetPageUptodate(page); 42748c2ecf20Sopenharmony_ci unlock_page(page); 42758c2ecf20Sopenharmony_ci put_page(page); 42768c2ecf20Sopenharmony_ci rdata->pages[i] = NULL; 42778c2ecf20Sopenharmony_ci rdata->nr_pages--; 42788c2ecf20Sopenharmony_ci continue; 42798c2ecf20Sopenharmony_ci } else { 42808c2ecf20Sopenharmony_ci /* no need to hold page hostage */ 42818c2ecf20Sopenharmony_ci lru_cache_add(page); 42828c2ecf20Sopenharmony_ci unlock_page(page); 42838c2ecf20Sopenharmony_ci put_page(page); 42848c2ecf20Sopenharmony_ci rdata->pages[i] = NULL; 42858c2ecf20Sopenharmony_ci rdata->nr_pages--; 42868c2ecf20Sopenharmony_ci continue; 42878c2ecf20Sopenharmony_ci } 42888c2ecf20Sopenharmony_ci 42898c2ecf20Sopenharmony_ci if (iter) 42908c2ecf20Sopenharmony_ci result = copy_page_from_iter( 42918c2ecf20Sopenharmony_ci page, page_offset, n, iter); 42928c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_SMB_DIRECT 42938c2ecf20Sopenharmony_ci else if (rdata->mr) 42948c2ecf20Sopenharmony_ci result = n; 42958c2ecf20Sopenharmony_ci#endif 42968c2ecf20Sopenharmony_ci else 42978c2ecf20Sopenharmony_ci result = cifs_read_page_from_socket( 42988c2ecf20Sopenharmony_ci server, page, page_offset, n); 42998c2ecf20Sopenharmony_ci if (result < 0) 43008c2ecf20Sopenharmony_ci break; 43018c2ecf20Sopenharmony_ci 43028c2ecf20Sopenharmony_ci rdata->got_bytes += result; 43038c2ecf20Sopenharmony_ci } 43048c2ecf20Sopenharmony_ci 43058c2ecf20Sopenharmony_ci return result != -ECONNABORTED && rdata->got_bytes > 0 ? 43068c2ecf20Sopenharmony_ci rdata->got_bytes : result; 43078c2ecf20Sopenharmony_ci} 43088c2ecf20Sopenharmony_ci 43098c2ecf20Sopenharmony_cistatic int 43108c2ecf20Sopenharmony_cicifs_readpages_read_into_pages(struct TCP_Server_Info *server, 43118c2ecf20Sopenharmony_ci struct cifs_readdata *rdata, unsigned int len) 43128c2ecf20Sopenharmony_ci{ 43138c2ecf20Sopenharmony_ci return readpages_fill_pages(server, rdata, NULL, len); 43148c2ecf20Sopenharmony_ci} 43158c2ecf20Sopenharmony_ci 43168c2ecf20Sopenharmony_cistatic int 43178c2ecf20Sopenharmony_cicifs_readpages_copy_into_pages(struct TCP_Server_Info *server, 43188c2ecf20Sopenharmony_ci struct cifs_readdata *rdata, 43198c2ecf20Sopenharmony_ci struct iov_iter *iter) 43208c2ecf20Sopenharmony_ci{ 43218c2ecf20Sopenharmony_ci return readpages_fill_pages(server, rdata, iter, iter->count); 43228c2ecf20Sopenharmony_ci} 43238c2ecf20Sopenharmony_ci 43248c2ecf20Sopenharmony_cistatic int 43258c2ecf20Sopenharmony_cireadpages_get_pages(struct address_space *mapping, struct list_head *page_list, 43268c2ecf20Sopenharmony_ci unsigned int rsize, struct list_head *tmplist, 43278c2ecf20Sopenharmony_ci unsigned int *nr_pages, loff_t *offset, unsigned int *bytes) 43288c2ecf20Sopenharmony_ci{ 43298c2ecf20Sopenharmony_ci struct page *page, *tpage; 43308c2ecf20Sopenharmony_ci unsigned int expected_index; 43318c2ecf20Sopenharmony_ci int rc; 43328c2ecf20Sopenharmony_ci gfp_t gfp = readahead_gfp_mask(mapping); 43338c2ecf20Sopenharmony_ci 43348c2ecf20Sopenharmony_ci INIT_LIST_HEAD(tmplist); 43358c2ecf20Sopenharmony_ci 43368c2ecf20Sopenharmony_ci page = lru_to_page(page_list); 43378c2ecf20Sopenharmony_ci 43388c2ecf20Sopenharmony_ci /* 43398c2ecf20Sopenharmony_ci * Lock the page and put it in the cache. Since no one else 43408c2ecf20Sopenharmony_ci * should have access to this page, we're safe to simply set 43418c2ecf20Sopenharmony_ci * PG_locked without checking it first. 43428c2ecf20Sopenharmony_ci */ 43438c2ecf20Sopenharmony_ci __SetPageLocked(page); 43448c2ecf20Sopenharmony_ci rc = add_to_page_cache_locked(page, mapping, 43458c2ecf20Sopenharmony_ci page->index, gfp); 43468c2ecf20Sopenharmony_ci 43478c2ecf20Sopenharmony_ci /* give up if we can't stick it in the cache */ 43488c2ecf20Sopenharmony_ci if (rc) { 43498c2ecf20Sopenharmony_ci __ClearPageLocked(page); 43508c2ecf20Sopenharmony_ci return rc; 43518c2ecf20Sopenharmony_ci } 43528c2ecf20Sopenharmony_ci 43538c2ecf20Sopenharmony_ci /* move first page to the tmplist */ 43548c2ecf20Sopenharmony_ci *offset = (loff_t)page->index << PAGE_SHIFT; 43558c2ecf20Sopenharmony_ci *bytes = PAGE_SIZE; 43568c2ecf20Sopenharmony_ci *nr_pages = 1; 43578c2ecf20Sopenharmony_ci list_move_tail(&page->lru, tmplist); 43588c2ecf20Sopenharmony_ci 43598c2ecf20Sopenharmony_ci /* now try and add more pages onto the request */ 43608c2ecf20Sopenharmony_ci expected_index = page->index + 1; 43618c2ecf20Sopenharmony_ci list_for_each_entry_safe_reverse(page, tpage, page_list, lru) { 43628c2ecf20Sopenharmony_ci /* discontinuity ? */ 43638c2ecf20Sopenharmony_ci if (page->index != expected_index) 43648c2ecf20Sopenharmony_ci break; 43658c2ecf20Sopenharmony_ci 43668c2ecf20Sopenharmony_ci /* would this page push the read over the rsize? */ 43678c2ecf20Sopenharmony_ci if (*bytes + PAGE_SIZE > rsize) 43688c2ecf20Sopenharmony_ci break; 43698c2ecf20Sopenharmony_ci 43708c2ecf20Sopenharmony_ci __SetPageLocked(page); 43718c2ecf20Sopenharmony_ci rc = add_to_page_cache_locked(page, mapping, page->index, gfp); 43728c2ecf20Sopenharmony_ci if (rc) { 43738c2ecf20Sopenharmony_ci __ClearPageLocked(page); 43748c2ecf20Sopenharmony_ci break; 43758c2ecf20Sopenharmony_ci } 43768c2ecf20Sopenharmony_ci list_move_tail(&page->lru, tmplist); 43778c2ecf20Sopenharmony_ci (*bytes) += PAGE_SIZE; 43788c2ecf20Sopenharmony_ci expected_index++; 43798c2ecf20Sopenharmony_ci (*nr_pages)++; 43808c2ecf20Sopenharmony_ci } 43818c2ecf20Sopenharmony_ci return rc; 43828c2ecf20Sopenharmony_ci} 43838c2ecf20Sopenharmony_ci 43848c2ecf20Sopenharmony_cistatic int cifs_readpages(struct file *file, struct address_space *mapping, 43858c2ecf20Sopenharmony_ci struct list_head *page_list, unsigned num_pages) 43868c2ecf20Sopenharmony_ci{ 43878c2ecf20Sopenharmony_ci int rc; 43888c2ecf20Sopenharmony_ci int err = 0; 43898c2ecf20Sopenharmony_ci struct list_head tmplist; 43908c2ecf20Sopenharmony_ci struct cifsFileInfo *open_file = file->private_data; 43918c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file); 43928c2ecf20Sopenharmony_ci struct TCP_Server_Info *server; 43938c2ecf20Sopenharmony_ci pid_t pid; 43948c2ecf20Sopenharmony_ci unsigned int xid; 43958c2ecf20Sopenharmony_ci 43968c2ecf20Sopenharmony_ci xid = get_xid(); 43978c2ecf20Sopenharmony_ci /* 43988c2ecf20Sopenharmony_ci * Reads as many pages as possible from fscache. Returns -ENOBUFS 43998c2ecf20Sopenharmony_ci * immediately if the cookie is negative 44008c2ecf20Sopenharmony_ci * 44018c2ecf20Sopenharmony_ci * After this point, every page in the list might have PG_fscache set, 44028c2ecf20Sopenharmony_ci * so we will need to clean that up off of every page we don't use. 44038c2ecf20Sopenharmony_ci */ 44048c2ecf20Sopenharmony_ci rc = cifs_readpages_from_fscache(mapping->host, mapping, page_list, 44058c2ecf20Sopenharmony_ci &num_pages); 44068c2ecf20Sopenharmony_ci if (rc == 0) { 44078c2ecf20Sopenharmony_ci free_xid(xid); 44088c2ecf20Sopenharmony_ci return rc; 44098c2ecf20Sopenharmony_ci } 44108c2ecf20Sopenharmony_ci 44118c2ecf20Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) 44128c2ecf20Sopenharmony_ci pid = open_file->pid; 44138c2ecf20Sopenharmony_ci else 44148c2ecf20Sopenharmony_ci pid = current->tgid; 44158c2ecf20Sopenharmony_ci 44168c2ecf20Sopenharmony_ci rc = 0; 44178c2ecf20Sopenharmony_ci server = cifs_pick_channel(tlink_tcon(open_file->tlink)->ses); 44188c2ecf20Sopenharmony_ci 44198c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: file=%p mapping=%p num_pages=%u\n", 44208c2ecf20Sopenharmony_ci __func__, file, mapping, num_pages); 44218c2ecf20Sopenharmony_ci 44228c2ecf20Sopenharmony_ci /* 44238c2ecf20Sopenharmony_ci * Start with the page at end of list and move it to private 44248c2ecf20Sopenharmony_ci * list. Do the same with any following pages until we hit 44258c2ecf20Sopenharmony_ci * the rsize limit, hit an index discontinuity, or run out of 44268c2ecf20Sopenharmony_ci * pages. Issue the async read and then start the loop again 44278c2ecf20Sopenharmony_ci * until the list is empty. 44288c2ecf20Sopenharmony_ci * 44298c2ecf20Sopenharmony_ci * Note that list order is important. The page_list is in 44308c2ecf20Sopenharmony_ci * the order of declining indexes. When we put the pages in 44318c2ecf20Sopenharmony_ci * the rdata->pages, then we want them in increasing order. 44328c2ecf20Sopenharmony_ci */ 44338c2ecf20Sopenharmony_ci while (!list_empty(page_list) && !err) { 44348c2ecf20Sopenharmony_ci unsigned int i, nr_pages, bytes, rsize; 44358c2ecf20Sopenharmony_ci loff_t offset; 44368c2ecf20Sopenharmony_ci struct page *page, *tpage; 44378c2ecf20Sopenharmony_ci struct cifs_readdata *rdata; 44388c2ecf20Sopenharmony_ci struct cifs_credits credits_on_stack; 44398c2ecf20Sopenharmony_ci struct cifs_credits *credits = &credits_on_stack; 44408c2ecf20Sopenharmony_ci 44418c2ecf20Sopenharmony_ci if (open_file->invalidHandle) { 44428c2ecf20Sopenharmony_ci rc = cifs_reopen_file(open_file, true); 44438c2ecf20Sopenharmony_ci if (rc == -EAGAIN) 44448c2ecf20Sopenharmony_ci continue; 44458c2ecf20Sopenharmony_ci else if (rc) 44468c2ecf20Sopenharmony_ci break; 44478c2ecf20Sopenharmony_ci } 44488c2ecf20Sopenharmony_ci 44498c2ecf20Sopenharmony_ci rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize, 44508c2ecf20Sopenharmony_ci &rsize, credits); 44518c2ecf20Sopenharmony_ci if (rc) 44528c2ecf20Sopenharmony_ci break; 44538c2ecf20Sopenharmony_ci 44548c2ecf20Sopenharmony_ci /* 44558c2ecf20Sopenharmony_ci * Give up immediately if rsize is too small to read an entire 44568c2ecf20Sopenharmony_ci * page. The VFS will fall back to readpage. We should never 44578c2ecf20Sopenharmony_ci * reach this point however since we set ra_pages to 0 when the 44588c2ecf20Sopenharmony_ci * rsize is smaller than a cache page. 44598c2ecf20Sopenharmony_ci */ 44608c2ecf20Sopenharmony_ci if (unlikely(rsize < PAGE_SIZE)) { 44618c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 44628c2ecf20Sopenharmony_ci free_xid(xid); 44638c2ecf20Sopenharmony_ci return 0; 44648c2ecf20Sopenharmony_ci } 44658c2ecf20Sopenharmony_ci 44668c2ecf20Sopenharmony_ci nr_pages = 0; 44678c2ecf20Sopenharmony_ci err = readpages_get_pages(mapping, page_list, rsize, &tmplist, 44688c2ecf20Sopenharmony_ci &nr_pages, &offset, &bytes); 44698c2ecf20Sopenharmony_ci if (!nr_pages) { 44708c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 44718c2ecf20Sopenharmony_ci break; 44728c2ecf20Sopenharmony_ci } 44738c2ecf20Sopenharmony_ci 44748c2ecf20Sopenharmony_ci rdata = cifs_readdata_alloc(nr_pages, cifs_readv_complete); 44758c2ecf20Sopenharmony_ci if (!rdata) { 44768c2ecf20Sopenharmony_ci /* best to give up if we're out of mem */ 44778c2ecf20Sopenharmony_ci list_for_each_entry_safe(page, tpage, &tmplist, lru) { 44788c2ecf20Sopenharmony_ci list_del(&page->lru); 44798c2ecf20Sopenharmony_ci lru_cache_add(page); 44808c2ecf20Sopenharmony_ci unlock_page(page); 44818c2ecf20Sopenharmony_ci put_page(page); 44828c2ecf20Sopenharmony_ci } 44838c2ecf20Sopenharmony_ci rc = -ENOMEM; 44848c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, credits, 0); 44858c2ecf20Sopenharmony_ci break; 44868c2ecf20Sopenharmony_ci } 44878c2ecf20Sopenharmony_ci 44888c2ecf20Sopenharmony_ci rdata->cfile = cifsFileInfo_get(open_file); 44898c2ecf20Sopenharmony_ci rdata->server = server; 44908c2ecf20Sopenharmony_ci rdata->mapping = mapping; 44918c2ecf20Sopenharmony_ci rdata->offset = offset; 44928c2ecf20Sopenharmony_ci rdata->bytes = bytes; 44938c2ecf20Sopenharmony_ci rdata->pid = pid; 44948c2ecf20Sopenharmony_ci rdata->pagesz = PAGE_SIZE; 44958c2ecf20Sopenharmony_ci rdata->tailsz = PAGE_SIZE; 44968c2ecf20Sopenharmony_ci rdata->read_into_pages = cifs_readpages_read_into_pages; 44978c2ecf20Sopenharmony_ci rdata->copy_into_pages = cifs_readpages_copy_into_pages; 44988c2ecf20Sopenharmony_ci rdata->credits = credits_on_stack; 44998c2ecf20Sopenharmony_ci 45008c2ecf20Sopenharmony_ci list_for_each_entry_safe(page, tpage, &tmplist, lru) { 45018c2ecf20Sopenharmony_ci list_del(&page->lru); 45028c2ecf20Sopenharmony_ci rdata->pages[rdata->nr_pages++] = page; 45038c2ecf20Sopenharmony_ci } 45048c2ecf20Sopenharmony_ci 45058c2ecf20Sopenharmony_ci rc = adjust_credits(server, &rdata->credits, rdata->bytes); 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci if (!rc) { 45088c2ecf20Sopenharmony_ci if (rdata->cfile->invalidHandle) 45098c2ecf20Sopenharmony_ci rc = -EAGAIN; 45108c2ecf20Sopenharmony_ci else 45118c2ecf20Sopenharmony_ci rc = server->ops->async_readv(rdata); 45128c2ecf20Sopenharmony_ci } 45138c2ecf20Sopenharmony_ci 45148c2ecf20Sopenharmony_ci if (rc) { 45158c2ecf20Sopenharmony_ci add_credits_and_wake_if(server, &rdata->credits, 0); 45168c2ecf20Sopenharmony_ci for (i = 0; i < rdata->nr_pages; i++) { 45178c2ecf20Sopenharmony_ci page = rdata->pages[i]; 45188c2ecf20Sopenharmony_ci lru_cache_add(page); 45198c2ecf20Sopenharmony_ci unlock_page(page); 45208c2ecf20Sopenharmony_ci put_page(page); 45218c2ecf20Sopenharmony_ci } 45228c2ecf20Sopenharmony_ci /* Fallback to the readpage in error/reconnect cases */ 45238c2ecf20Sopenharmony_ci kref_put(&rdata->refcount, cifs_readdata_release); 45248c2ecf20Sopenharmony_ci break; 45258c2ecf20Sopenharmony_ci } 45268c2ecf20Sopenharmony_ci 45278c2ecf20Sopenharmony_ci kref_put(&rdata->refcount, cifs_readdata_release); 45288c2ecf20Sopenharmony_ci } 45298c2ecf20Sopenharmony_ci 45308c2ecf20Sopenharmony_ci /* Any pages that have been shown to fscache but didn't get added to 45318c2ecf20Sopenharmony_ci * the pagecache must be uncached before they get returned to the 45328c2ecf20Sopenharmony_ci * allocator. 45338c2ecf20Sopenharmony_ci */ 45348c2ecf20Sopenharmony_ci cifs_fscache_readpages_cancel(mapping->host, page_list); 45358c2ecf20Sopenharmony_ci free_xid(xid); 45368c2ecf20Sopenharmony_ci return rc; 45378c2ecf20Sopenharmony_ci} 45388c2ecf20Sopenharmony_ci 45398c2ecf20Sopenharmony_ci/* 45408c2ecf20Sopenharmony_ci * cifs_readpage_worker must be called with the page pinned 45418c2ecf20Sopenharmony_ci */ 45428c2ecf20Sopenharmony_cistatic int cifs_readpage_worker(struct file *file, struct page *page, 45438c2ecf20Sopenharmony_ci loff_t *poffset) 45448c2ecf20Sopenharmony_ci{ 45458c2ecf20Sopenharmony_ci char *read_data; 45468c2ecf20Sopenharmony_ci int rc; 45478c2ecf20Sopenharmony_ci 45488c2ecf20Sopenharmony_ci /* Is the page cached? */ 45498c2ecf20Sopenharmony_ci rc = cifs_readpage_from_fscache(file_inode(file), page); 45508c2ecf20Sopenharmony_ci if (rc == 0) 45518c2ecf20Sopenharmony_ci goto read_complete; 45528c2ecf20Sopenharmony_ci 45538c2ecf20Sopenharmony_ci read_data = kmap(page); 45548c2ecf20Sopenharmony_ci /* for reads over a certain size could initiate async read ahead */ 45558c2ecf20Sopenharmony_ci 45568c2ecf20Sopenharmony_ci rc = cifs_read(file, read_data, PAGE_SIZE, poffset); 45578c2ecf20Sopenharmony_ci 45588c2ecf20Sopenharmony_ci if (rc < 0) 45598c2ecf20Sopenharmony_ci goto io_error; 45608c2ecf20Sopenharmony_ci else 45618c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Bytes read %d\n", rc); 45628c2ecf20Sopenharmony_ci 45638c2ecf20Sopenharmony_ci /* we do not want atime to be less than mtime, it broke some apps */ 45648c2ecf20Sopenharmony_ci file_inode(file)->i_atime = current_time(file_inode(file)); 45658c2ecf20Sopenharmony_ci if (timespec64_compare(&(file_inode(file)->i_atime), &(file_inode(file)->i_mtime))) 45668c2ecf20Sopenharmony_ci file_inode(file)->i_atime = file_inode(file)->i_mtime; 45678c2ecf20Sopenharmony_ci else 45688c2ecf20Sopenharmony_ci file_inode(file)->i_atime = current_time(file_inode(file)); 45698c2ecf20Sopenharmony_ci 45708c2ecf20Sopenharmony_ci if (PAGE_SIZE > rc) 45718c2ecf20Sopenharmony_ci memset(read_data + rc, 0, PAGE_SIZE - rc); 45728c2ecf20Sopenharmony_ci 45738c2ecf20Sopenharmony_ci flush_dcache_page(page); 45748c2ecf20Sopenharmony_ci SetPageUptodate(page); 45758c2ecf20Sopenharmony_ci 45768c2ecf20Sopenharmony_ci /* send this page to the cache */ 45778c2ecf20Sopenharmony_ci cifs_readpage_to_fscache(file_inode(file), page); 45788c2ecf20Sopenharmony_ci 45798c2ecf20Sopenharmony_ci rc = 0; 45808c2ecf20Sopenharmony_ci 45818c2ecf20Sopenharmony_ciio_error: 45828c2ecf20Sopenharmony_ci kunmap(page); 45838c2ecf20Sopenharmony_ci 45848c2ecf20Sopenharmony_ciread_complete: 45858c2ecf20Sopenharmony_ci unlock_page(page); 45868c2ecf20Sopenharmony_ci return rc; 45878c2ecf20Sopenharmony_ci} 45888c2ecf20Sopenharmony_ci 45898c2ecf20Sopenharmony_cistatic int cifs_readpage(struct file *file, struct page *page) 45908c2ecf20Sopenharmony_ci{ 45918c2ecf20Sopenharmony_ci loff_t offset = page_file_offset(page); 45928c2ecf20Sopenharmony_ci int rc = -EACCES; 45938c2ecf20Sopenharmony_ci unsigned int xid; 45948c2ecf20Sopenharmony_ci 45958c2ecf20Sopenharmony_ci xid = get_xid(); 45968c2ecf20Sopenharmony_ci 45978c2ecf20Sopenharmony_ci if (file->private_data == NULL) { 45988c2ecf20Sopenharmony_ci rc = -EBADF; 45998c2ecf20Sopenharmony_ci free_xid(xid); 46008c2ecf20Sopenharmony_ci return rc; 46018c2ecf20Sopenharmony_ci } 46028c2ecf20Sopenharmony_ci 46038c2ecf20Sopenharmony_ci cifs_dbg(FYI, "readpage %p at offset %d 0x%x\n", 46048c2ecf20Sopenharmony_ci page, (int)offset, (int)offset); 46058c2ecf20Sopenharmony_ci 46068c2ecf20Sopenharmony_ci rc = cifs_readpage_worker(file, page, &offset); 46078c2ecf20Sopenharmony_ci 46088c2ecf20Sopenharmony_ci free_xid(xid); 46098c2ecf20Sopenharmony_ci return rc; 46108c2ecf20Sopenharmony_ci} 46118c2ecf20Sopenharmony_ci 46128c2ecf20Sopenharmony_cistatic int is_inode_writable(struct cifsInodeInfo *cifs_inode) 46138c2ecf20Sopenharmony_ci{ 46148c2ecf20Sopenharmony_ci struct cifsFileInfo *open_file; 46158c2ecf20Sopenharmony_ci 46168c2ecf20Sopenharmony_ci spin_lock(&cifs_inode->open_file_lock); 46178c2ecf20Sopenharmony_ci list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { 46188c2ecf20Sopenharmony_ci if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { 46198c2ecf20Sopenharmony_ci spin_unlock(&cifs_inode->open_file_lock); 46208c2ecf20Sopenharmony_ci return 1; 46218c2ecf20Sopenharmony_ci } 46228c2ecf20Sopenharmony_ci } 46238c2ecf20Sopenharmony_ci spin_unlock(&cifs_inode->open_file_lock); 46248c2ecf20Sopenharmony_ci return 0; 46258c2ecf20Sopenharmony_ci} 46268c2ecf20Sopenharmony_ci 46278c2ecf20Sopenharmony_ci/* We do not want to update the file size from server for inodes 46288c2ecf20Sopenharmony_ci open for write - to avoid races with writepage extending 46298c2ecf20Sopenharmony_ci the file - in the future we could consider allowing 46308c2ecf20Sopenharmony_ci refreshing the inode only on increases in the file size 46318c2ecf20Sopenharmony_ci but this is tricky to do without racing with writebehind 46328c2ecf20Sopenharmony_ci page caching in the current Linux kernel design */ 46338c2ecf20Sopenharmony_cibool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file) 46348c2ecf20Sopenharmony_ci{ 46358c2ecf20Sopenharmony_ci if (!cifsInode) 46368c2ecf20Sopenharmony_ci return true; 46378c2ecf20Sopenharmony_ci 46388c2ecf20Sopenharmony_ci if (is_inode_writable(cifsInode)) { 46398c2ecf20Sopenharmony_ci /* This inode is open for write at least once */ 46408c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb; 46418c2ecf20Sopenharmony_ci 46428c2ecf20Sopenharmony_ci cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb); 46438c2ecf20Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { 46448c2ecf20Sopenharmony_ci /* since no page cache to corrupt on directio 46458c2ecf20Sopenharmony_ci we can change size safely */ 46468c2ecf20Sopenharmony_ci return true; 46478c2ecf20Sopenharmony_ci } 46488c2ecf20Sopenharmony_ci 46498c2ecf20Sopenharmony_ci if (i_size_read(&cifsInode->vfs_inode) < end_of_file) 46508c2ecf20Sopenharmony_ci return true; 46518c2ecf20Sopenharmony_ci 46528c2ecf20Sopenharmony_ci return false; 46538c2ecf20Sopenharmony_ci } else 46548c2ecf20Sopenharmony_ci return true; 46558c2ecf20Sopenharmony_ci} 46568c2ecf20Sopenharmony_ci 46578c2ecf20Sopenharmony_cistatic int cifs_write_begin(struct file *file, struct address_space *mapping, 46588c2ecf20Sopenharmony_ci loff_t pos, unsigned len, unsigned flags, 46598c2ecf20Sopenharmony_ci struct page **pagep, void **fsdata) 46608c2ecf20Sopenharmony_ci{ 46618c2ecf20Sopenharmony_ci int oncethru = 0; 46628c2ecf20Sopenharmony_ci pgoff_t index = pos >> PAGE_SHIFT; 46638c2ecf20Sopenharmony_ci loff_t offset = pos & (PAGE_SIZE - 1); 46648c2ecf20Sopenharmony_ci loff_t page_start = pos & PAGE_MASK; 46658c2ecf20Sopenharmony_ci loff_t i_size; 46668c2ecf20Sopenharmony_ci struct page *page; 46678c2ecf20Sopenharmony_ci int rc = 0; 46688c2ecf20Sopenharmony_ci 46698c2ecf20Sopenharmony_ci cifs_dbg(FYI, "write_begin from %lld len %d\n", (long long)pos, len); 46708c2ecf20Sopenharmony_ci 46718c2ecf20Sopenharmony_cistart: 46728c2ecf20Sopenharmony_ci page = grab_cache_page_write_begin(mapping, index, flags); 46738c2ecf20Sopenharmony_ci if (!page) { 46748c2ecf20Sopenharmony_ci rc = -ENOMEM; 46758c2ecf20Sopenharmony_ci goto out; 46768c2ecf20Sopenharmony_ci } 46778c2ecf20Sopenharmony_ci 46788c2ecf20Sopenharmony_ci if (PageUptodate(page)) 46798c2ecf20Sopenharmony_ci goto out; 46808c2ecf20Sopenharmony_ci 46818c2ecf20Sopenharmony_ci /* 46828c2ecf20Sopenharmony_ci * If we write a full page it will be up to date, no need to read from 46838c2ecf20Sopenharmony_ci * the server. If the write is short, we'll end up doing a sync write 46848c2ecf20Sopenharmony_ci * instead. 46858c2ecf20Sopenharmony_ci */ 46868c2ecf20Sopenharmony_ci if (len == PAGE_SIZE) 46878c2ecf20Sopenharmony_ci goto out; 46888c2ecf20Sopenharmony_ci 46898c2ecf20Sopenharmony_ci /* 46908c2ecf20Sopenharmony_ci * optimize away the read when we have an oplock, and we're not 46918c2ecf20Sopenharmony_ci * expecting to use any of the data we'd be reading in. That 46928c2ecf20Sopenharmony_ci * is, when the page lies beyond the EOF, or straddles the EOF 46938c2ecf20Sopenharmony_ci * and the write will cover all of the existing data. 46948c2ecf20Sopenharmony_ci */ 46958c2ecf20Sopenharmony_ci if (CIFS_CACHE_READ(CIFS_I(mapping->host))) { 46968c2ecf20Sopenharmony_ci i_size = i_size_read(mapping->host); 46978c2ecf20Sopenharmony_ci if (page_start >= i_size || 46988c2ecf20Sopenharmony_ci (offset == 0 && (pos + len) >= i_size)) { 46998c2ecf20Sopenharmony_ci zero_user_segments(page, 0, offset, 47008c2ecf20Sopenharmony_ci offset + len, 47018c2ecf20Sopenharmony_ci PAGE_SIZE); 47028c2ecf20Sopenharmony_ci /* 47038c2ecf20Sopenharmony_ci * PageChecked means that the parts of the page 47048c2ecf20Sopenharmony_ci * to which we're not writing are considered up 47058c2ecf20Sopenharmony_ci * to date. Once the data is copied to the 47068c2ecf20Sopenharmony_ci * page, it can be set uptodate. 47078c2ecf20Sopenharmony_ci */ 47088c2ecf20Sopenharmony_ci SetPageChecked(page); 47098c2ecf20Sopenharmony_ci goto out; 47108c2ecf20Sopenharmony_ci } 47118c2ecf20Sopenharmony_ci } 47128c2ecf20Sopenharmony_ci 47138c2ecf20Sopenharmony_ci if ((file->f_flags & O_ACCMODE) != O_WRONLY && !oncethru) { 47148c2ecf20Sopenharmony_ci /* 47158c2ecf20Sopenharmony_ci * might as well read a page, it is fast enough. If we get 47168c2ecf20Sopenharmony_ci * an error, we don't need to return it. cifs_write_end will 47178c2ecf20Sopenharmony_ci * do a sync write instead since PG_uptodate isn't set. 47188c2ecf20Sopenharmony_ci */ 47198c2ecf20Sopenharmony_ci cifs_readpage_worker(file, page, &page_start); 47208c2ecf20Sopenharmony_ci put_page(page); 47218c2ecf20Sopenharmony_ci oncethru = 1; 47228c2ecf20Sopenharmony_ci goto start; 47238c2ecf20Sopenharmony_ci } else { 47248c2ecf20Sopenharmony_ci /* we could try using another file handle if there is one - 47258c2ecf20Sopenharmony_ci but how would we lock it to prevent close of that handle 47268c2ecf20Sopenharmony_ci racing with this read? In any case 47278c2ecf20Sopenharmony_ci this will be written out by write_end so is fine */ 47288c2ecf20Sopenharmony_ci } 47298c2ecf20Sopenharmony_ciout: 47308c2ecf20Sopenharmony_ci *pagep = page; 47318c2ecf20Sopenharmony_ci return rc; 47328c2ecf20Sopenharmony_ci} 47338c2ecf20Sopenharmony_ci 47348c2ecf20Sopenharmony_cistatic int cifs_release_page(struct page *page, gfp_t gfp) 47358c2ecf20Sopenharmony_ci{ 47368c2ecf20Sopenharmony_ci if (PagePrivate(page)) 47378c2ecf20Sopenharmony_ci return 0; 47388c2ecf20Sopenharmony_ci 47398c2ecf20Sopenharmony_ci return cifs_fscache_release_page(page, gfp); 47408c2ecf20Sopenharmony_ci} 47418c2ecf20Sopenharmony_ci 47428c2ecf20Sopenharmony_cistatic void cifs_invalidate_page(struct page *page, unsigned int offset, 47438c2ecf20Sopenharmony_ci unsigned int length) 47448c2ecf20Sopenharmony_ci{ 47458c2ecf20Sopenharmony_ci struct cifsInodeInfo *cifsi = CIFS_I(page->mapping->host); 47468c2ecf20Sopenharmony_ci 47478c2ecf20Sopenharmony_ci if (offset == 0 && length == PAGE_SIZE) 47488c2ecf20Sopenharmony_ci cifs_fscache_invalidate_page(page, &cifsi->vfs_inode); 47498c2ecf20Sopenharmony_ci} 47508c2ecf20Sopenharmony_ci 47518c2ecf20Sopenharmony_cistatic int cifs_launder_page(struct page *page) 47528c2ecf20Sopenharmony_ci{ 47538c2ecf20Sopenharmony_ci int rc = 0; 47548c2ecf20Sopenharmony_ci loff_t range_start = page_offset(page); 47558c2ecf20Sopenharmony_ci loff_t range_end = range_start + (loff_t)(PAGE_SIZE - 1); 47568c2ecf20Sopenharmony_ci struct writeback_control wbc = { 47578c2ecf20Sopenharmony_ci .sync_mode = WB_SYNC_ALL, 47588c2ecf20Sopenharmony_ci .nr_to_write = 0, 47598c2ecf20Sopenharmony_ci .range_start = range_start, 47608c2ecf20Sopenharmony_ci .range_end = range_end, 47618c2ecf20Sopenharmony_ci }; 47628c2ecf20Sopenharmony_ci 47638c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Launder page: %p\n", page); 47648c2ecf20Sopenharmony_ci 47658c2ecf20Sopenharmony_ci if (clear_page_dirty_for_io(page)) 47668c2ecf20Sopenharmony_ci rc = cifs_writepage_locked(page, &wbc); 47678c2ecf20Sopenharmony_ci 47688c2ecf20Sopenharmony_ci cifs_fscache_invalidate_page(page, page->mapping->host); 47698c2ecf20Sopenharmony_ci return rc; 47708c2ecf20Sopenharmony_ci} 47718c2ecf20Sopenharmony_ci 47728c2ecf20Sopenharmony_civoid cifs_oplock_break(struct work_struct *work) 47738c2ecf20Sopenharmony_ci{ 47748c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, 47758c2ecf20Sopenharmony_ci oplock_break); 47768c2ecf20Sopenharmony_ci struct inode *inode = d_inode(cfile->dentry); 47778c2ecf20Sopenharmony_ci struct cifsInodeInfo *cinode = CIFS_I(inode); 47788c2ecf20Sopenharmony_ci struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); 47798c2ecf20Sopenharmony_ci struct TCP_Server_Info *server = tcon->ses->server; 47808c2ecf20Sopenharmony_ci int rc = 0; 47818c2ecf20Sopenharmony_ci bool purge_cache = false; 47828c2ecf20Sopenharmony_ci 47838c2ecf20Sopenharmony_ci wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS, 47848c2ecf20Sopenharmony_ci TASK_UNINTERRUPTIBLE); 47858c2ecf20Sopenharmony_ci 47868c2ecf20Sopenharmony_ci server->ops->downgrade_oplock(server, cinode, cfile->oplock_level, 47878c2ecf20Sopenharmony_ci cfile->oplock_epoch, &purge_cache); 47888c2ecf20Sopenharmony_ci 47898c2ecf20Sopenharmony_ci if (!CIFS_CACHE_WRITE(cinode) && CIFS_CACHE_READ(cinode) && 47908c2ecf20Sopenharmony_ci cifs_has_mand_locks(cinode)) { 47918c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Reset oplock to None for inode=%p due to mand locks\n", 47928c2ecf20Sopenharmony_ci inode); 47938c2ecf20Sopenharmony_ci cinode->oplock = 0; 47948c2ecf20Sopenharmony_ci } 47958c2ecf20Sopenharmony_ci 47968c2ecf20Sopenharmony_ci if (inode && S_ISREG(inode->i_mode)) { 47978c2ecf20Sopenharmony_ci if (CIFS_CACHE_READ(cinode)) 47988c2ecf20Sopenharmony_ci break_lease(inode, O_RDONLY); 47998c2ecf20Sopenharmony_ci else 48008c2ecf20Sopenharmony_ci break_lease(inode, O_WRONLY); 48018c2ecf20Sopenharmony_ci rc = filemap_fdatawrite(inode->i_mapping); 48028c2ecf20Sopenharmony_ci if (!CIFS_CACHE_READ(cinode) || purge_cache) { 48038c2ecf20Sopenharmony_ci rc = filemap_fdatawait(inode->i_mapping); 48048c2ecf20Sopenharmony_ci mapping_set_error(inode->i_mapping, rc); 48058c2ecf20Sopenharmony_ci cifs_zap_mapping(inode); 48068c2ecf20Sopenharmony_ci } 48078c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Oplock flush inode %p rc %d\n", inode, rc); 48088c2ecf20Sopenharmony_ci if (CIFS_CACHE_WRITE(cinode)) 48098c2ecf20Sopenharmony_ci goto oplock_break_ack; 48108c2ecf20Sopenharmony_ci } 48118c2ecf20Sopenharmony_ci 48128c2ecf20Sopenharmony_ci rc = cifs_push_locks(cfile); 48138c2ecf20Sopenharmony_ci if (rc) 48148c2ecf20Sopenharmony_ci cifs_dbg(VFS, "Push locks rc = %d\n", rc); 48158c2ecf20Sopenharmony_ci 48168c2ecf20Sopenharmony_cioplock_break_ack: 48178c2ecf20Sopenharmony_ci /* 48188c2ecf20Sopenharmony_ci * releasing stale oplock after recent reconnect of smb session using 48198c2ecf20Sopenharmony_ci * a now incorrect file handle is not a data integrity issue but do 48208c2ecf20Sopenharmony_ci * not bother sending an oplock release if session to server still is 48218c2ecf20Sopenharmony_ci * disconnected since oplock already released by the server 48228c2ecf20Sopenharmony_ci */ 48238c2ecf20Sopenharmony_ci if (!cfile->oplock_break_cancelled) { 48248c2ecf20Sopenharmony_ci rc = tcon->ses->server->ops->oplock_response(tcon, &cfile->fid, 48258c2ecf20Sopenharmony_ci cinode); 48268c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Oplock release rc = %d\n", rc); 48278c2ecf20Sopenharmony_ci } 48288c2ecf20Sopenharmony_ci _cifsFileInfo_put(cfile, false /* do not wait for ourself */, false); 48298c2ecf20Sopenharmony_ci cifs_done_oplock_break(cinode); 48308c2ecf20Sopenharmony_ci} 48318c2ecf20Sopenharmony_ci 48328c2ecf20Sopenharmony_ci/* 48338c2ecf20Sopenharmony_ci * The presence of cifs_direct_io() in the address space ops vector 48348c2ecf20Sopenharmony_ci * allowes open() O_DIRECT flags which would have failed otherwise. 48358c2ecf20Sopenharmony_ci * 48368c2ecf20Sopenharmony_ci * In the non-cached mode (mount with cache=none), we shunt off direct read and write requests 48378c2ecf20Sopenharmony_ci * so this method should never be called. 48388c2ecf20Sopenharmony_ci * 48398c2ecf20Sopenharmony_ci * Direct IO is not yet supported in the cached mode. 48408c2ecf20Sopenharmony_ci */ 48418c2ecf20Sopenharmony_cistatic ssize_t 48428c2ecf20Sopenharmony_cicifs_direct_io(struct kiocb *iocb, struct iov_iter *iter) 48438c2ecf20Sopenharmony_ci{ 48448c2ecf20Sopenharmony_ci /* 48458c2ecf20Sopenharmony_ci * FIXME 48468c2ecf20Sopenharmony_ci * Eventually need to support direct IO for non forcedirectio mounts 48478c2ecf20Sopenharmony_ci */ 48488c2ecf20Sopenharmony_ci return -EINVAL; 48498c2ecf20Sopenharmony_ci} 48508c2ecf20Sopenharmony_ci 48518c2ecf20Sopenharmony_cistatic int cifs_swap_activate(struct swap_info_struct *sis, 48528c2ecf20Sopenharmony_ci struct file *swap_file, sector_t *span) 48538c2ecf20Sopenharmony_ci{ 48548c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile = swap_file->private_data; 48558c2ecf20Sopenharmony_ci struct inode *inode = swap_file->f_mapping->host; 48568c2ecf20Sopenharmony_ci unsigned long blocks; 48578c2ecf20Sopenharmony_ci long long isize; 48588c2ecf20Sopenharmony_ci 48598c2ecf20Sopenharmony_ci cifs_dbg(FYI, "swap activate\n"); 48608c2ecf20Sopenharmony_ci 48618c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 48628c2ecf20Sopenharmony_ci blocks = inode->i_blocks; 48638c2ecf20Sopenharmony_ci isize = inode->i_size; 48648c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 48658c2ecf20Sopenharmony_ci if (blocks*512 < isize) { 48668c2ecf20Sopenharmony_ci pr_warn("swap activate: swapfile has holes\n"); 48678c2ecf20Sopenharmony_ci return -EINVAL; 48688c2ecf20Sopenharmony_ci } 48698c2ecf20Sopenharmony_ci *span = sis->pages; 48708c2ecf20Sopenharmony_ci 48718c2ecf20Sopenharmony_ci pr_warn_once("Swap support over SMB3 is experimental\n"); 48728c2ecf20Sopenharmony_ci 48738c2ecf20Sopenharmony_ci /* 48748c2ecf20Sopenharmony_ci * TODO: consider adding ACL (or documenting how) to prevent other 48758c2ecf20Sopenharmony_ci * users (on this or other systems) from reading it 48768c2ecf20Sopenharmony_ci */ 48778c2ecf20Sopenharmony_ci 48788c2ecf20Sopenharmony_ci 48798c2ecf20Sopenharmony_ci /* TODO: add sk_set_memalloc(inet) or similar */ 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ci if (cfile) 48828c2ecf20Sopenharmony_ci cfile->swapfile = true; 48838c2ecf20Sopenharmony_ci /* 48848c2ecf20Sopenharmony_ci * TODO: Since file already open, we can't open with DENY_ALL here 48858c2ecf20Sopenharmony_ci * but we could add call to grab a byte range lock to prevent others 48868c2ecf20Sopenharmony_ci * from reading or writing the file 48878c2ecf20Sopenharmony_ci */ 48888c2ecf20Sopenharmony_ci 48898c2ecf20Sopenharmony_ci return 0; 48908c2ecf20Sopenharmony_ci} 48918c2ecf20Sopenharmony_ci 48928c2ecf20Sopenharmony_cistatic void cifs_swap_deactivate(struct file *file) 48938c2ecf20Sopenharmony_ci{ 48948c2ecf20Sopenharmony_ci struct cifsFileInfo *cfile = file->private_data; 48958c2ecf20Sopenharmony_ci 48968c2ecf20Sopenharmony_ci cifs_dbg(FYI, "swap deactivate\n"); 48978c2ecf20Sopenharmony_ci 48988c2ecf20Sopenharmony_ci /* TODO: undo sk_set_memalloc(inet) will eventually be needed */ 48998c2ecf20Sopenharmony_ci 49008c2ecf20Sopenharmony_ci if (cfile) 49018c2ecf20Sopenharmony_ci cfile->swapfile = false; 49028c2ecf20Sopenharmony_ci 49038c2ecf20Sopenharmony_ci /* do we need to unpin (or unlock) the file */ 49048c2ecf20Sopenharmony_ci} 49058c2ecf20Sopenharmony_ci 49068c2ecf20Sopenharmony_ciconst struct address_space_operations cifs_addr_ops = { 49078c2ecf20Sopenharmony_ci .readpage = cifs_readpage, 49088c2ecf20Sopenharmony_ci .readpages = cifs_readpages, 49098c2ecf20Sopenharmony_ci .writepage = cifs_writepage, 49108c2ecf20Sopenharmony_ci .writepages = cifs_writepages, 49118c2ecf20Sopenharmony_ci .write_begin = cifs_write_begin, 49128c2ecf20Sopenharmony_ci .write_end = cifs_write_end, 49138c2ecf20Sopenharmony_ci .set_page_dirty = __set_page_dirty_nobuffers, 49148c2ecf20Sopenharmony_ci .releasepage = cifs_release_page, 49158c2ecf20Sopenharmony_ci .direct_IO = cifs_direct_io, 49168c2ecf20Sopenharmony_ci .invalidatepage = cifs_invalidate_page, 49178c2ecf20Sopenharmony_ci .launder_page = cifs_launder_page, 49188c2ecf20Sopenharmony_ci /* 49198c2ecf20Sopenharmony_ci * TODO: investigate and if useful we could add an cifs_migratePage 49208c2ecf20Sopenharmony_ci * helper (under an CONFIG_MIGRATION) in the future, and also 49218c2ecf20Sopenharmony_ci * investigate and add an is_dirty_writeback helper if needed 49228c2ecf20Sopenharmony_ci */ 49238c2ecf20Sopenharmony_ci .swap_activate = cifs_swap_activate, 49248c2ecf20Sopenharmony_ci .swap_deactivate = cifs_swap_deactivate, 49258c2ecf20Sopenharmony_ci}; 49268c2ecf20Sopenharmony_ci 49278c2ecf20Sopenharmony_ci/* 49288c2ecf20Sopenharmony_ci * cifs_readpages requires the server to support a buffer large enough to 49298c2ecf20Sopenharmony_ci * contain the header plus one complete page of data. Otherwise, we need 49308c2ecf20Sopenharmony_ci * to leave cifs_readpages out of the address space operations. 49318c2ecf20Sopenharmony_ci */ 49328c2ecf20Sopenharmony_ciconst struct address_space_operations cifs_addr_ops_smallbuf = { 49338c2ecf20Sopenharmony_ci .readpage = cifs_readpage, 49348c2ecf20Sopenharmony_ci .writepage = cifs_writepage, 49358c2ecf20Sopenharmony_ci .writepages = cifs_writepages, 49368c2ecf20Sopenharmony_ci .write_begin = cifs_write_begin, 49378c2ecf20Sopenharmony_ci .write_end = cifs_write_end, 49388c2ecf20Sopenharmony_ci .set_page_dirty = __set_page_dirty_nobuffers, 49398c2ecf20Sopenharmony_ci .releasepage = cifs_release_page, 49408c2ecf20Sopenharmony_ci .invalidatepage = cifs_invalidate_page, 49418c2ecf20Sopenharmony_ci .launder_page = cifs_launder_page, 49428c2ecf20Sopenharmony_ci}; 4943