162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/nfs/file.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1992 Rick Sladkey 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/fs.h> 862306a36Sopenharmony_ci#include <linux/file.h> 962306a36Sopenharmony_ci#include <linux/falloc.h> 1062306a36Sopenharmony_ci#include <linux/mount.h> 1162306a36Sopenharmony_ci#include <linux/nfs_fs.h> 1262306a36Sopenharmony_ci#include <linux/nfs_ssc.h> 1362306a36Sopenharmony_ci#include "delegation.h" 1462306a36Sopenharmony_ci#include "internal.h" 1562306a36Sopenharmony_ci#include "iostat.h" 1662306a36Sopenharmony_ci#include "fscache.h" 1762306a36Sopenharmony_ci#include "pnfs.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "nfstrace.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#ifdef CONFIG_NFS_V4_2 2262306a36Sopenharmony_ci#include "nfs42.h" 2362306a36Sopenharmony_ci#endif 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define NFSDBG_FACILITY NFSDBG_FILE 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int 2862306a36Sopenharmony_cinfs4_file_open(struct inode *inode, struct file *filp) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct nfs_open_context *ctx; 3162306a36Sopenharmony_ci struct dentry *dentry = file_dentry(filp); 3262306a36Sopenharmony_ci struct dentry *parent = NULL; 3362306a36Sopenharmony_ci struct inode *dir; 3462306a36Sopenharmony_ci unsigned openflags = filp->f_flags; 3562306a36Sopenharmony_ci struct iattr attr; 3662306a36Sopenharmony_ci int err; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci /* 3962306a36Sopenharmony_ci * If no cached dentry exists or if it's negative, NFSv4 handled the 4062306a36Sopenharmony_ci * opens in ->lookup() or ->create(). 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * We only get this far for a cached positive dentry. We skipped 4362306a36Sopenharmony_ci * revalidation, so handle it here by dropping the dentry and returning 4462306a36Sopenharmony_ci * -EOPENSTALE. The VFS will retry the lookup/create/open. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci dprintk("NFS: open file(%pd2)\n", dentry); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci err = nfs_check_flags(openflags); 5062306a36Sopenharmony_ci if (err) 5162306a36Sopenharmony_ci return err; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci /* We can't create new files here */ 5462306a36Sopenharmony_ci openflags &= ~(O_CREAT|O_EXCL); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci parent = dget_parent(dentry); 5762306a36Sopenharmony_ci dir = d_inode(parent); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci ctx = alloc_nfs_open_context(file_dentry(filp), 6062306a36Sopenharmony_ci flags_to_mode(openflags), filp); 6162306a36Sopenharmony_ci err = PTR_ERR(ctx); 6262306a36Sopenharmony_ci if (IS_ERR(ctx)) 6362306a36Sopenharmony_ci goto out; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci attr.ia_valid = ATTR_OPEN; 6662306a36Sopenharmony_ci if (openflags & O_TRUNC) { 6762306a36Sopenharmony_ci attr.ia_valid |= ATTR_SIZE; 6862306a36Sopenharmony_ci attr.ia_size = 0; 6962306a36Sopenharmony_ci filemap_write_and_wait(inode->i_mapping); 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, NULL); 7362306a36Sopenharmony_ci if (IS_ERR(inode)) { 7462306a36Sopenharmony_ci err = PTR_ERR(inode); 7562306a36Sopenharmony_ci switch (err) { 7662306a36Sopenharmony_ci default: 7762306a36Sopenharmony_ci goto out_put_ctx; 7862306a36Sopenharmony_ci case -ENOENT: 7962306a36Sopenharmony_ci case -ESTALE: 8062306a36Sopenharmony_ci case -EISDIR: 8162306a36Sopenharmony_ci case -ENOTDIR: 8262306a36Sopenharmony_ci case -ELOOP: 8362306a36Sopenharmony_ci goto out_drop; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci if (inode != d_inode(dentry)) 8762306a36Sopenharmony_ci goto out_drop; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci nfs_file_set_open_context(filp, ctx); 9062306a36Sopenharmony_ci nfs_fscache_open_file(inode, filp); 9162306a36Sopenharmony_ci err = 0; 9262306a36Sopenharmony_ci filp->f_mode |= FMODE_CAN_ODIRECT; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ciout_put_ctx: 9562306a36Sopenharmony_ci put_nfs_open_context(ctx); 9662306a36Sopenharmony_ciout: 9762306a36Sopenharmony_ci dput(parent); 9862306a36Sopenharmony_ci return err; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ciout_drop: 10162306a36Sopenharmony_ci d_drop(dentry); 10262306a36Sopenharmony_ci err = -EOPENSTALE; 10362306a36Sopenharmony_ci goto out_put_ctx; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* 10762306a36Sopenharmony_ci * Flush all dirty pages, and check for write errors. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_cistatic int 11062306a36Sopenharmony_cinfs4_file_flush(struct file *file, fl_owner_t id) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct inode *inode = file_inode(file); 11362306a36Sopenharmony_ci errseq_t since; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci dprintk("NFS: flush(%pD2)\n", file); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_VFSFLUSH); 11862306a36Sopenharmony_ci if ((file->f_mode & FMODE_WRITE) == 0) 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* 12262306a36Sopenharmony_ci * If we're holding a write delegation, then check if we're required 12362306a36Sopenharmony_ci * to flush the i/o on close. If not, then just start the i/o now. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci if (!nfs4_delegation_flush_on_close(inode)) 12662306a36Sopenharmony_ci return filemap_fdatawrite(file->f_mapping); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Flush writes to the server and return any errors */ 12962306a36Sopenharmony_ci since = filemap_sample_wb_err(file->f_mapping); 13062306a36Sopenharmony_ci nfs_wb_all(inode); 13162306a36Sopenharmony_ci return filemap_check_wb_err(file->f_mapping, since); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci#ifdef CONFIG_NFS_V4_2 13562306a36Sopenharmony_cistatic ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in, 13662306a36Sopenharmony_ci struct file *file_out, loff_t pos_out, 13762306a36Sopenharmony_ci size_t count, unsigned int flags) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct nfs42_copy_notify_res *cn_resp = NULL; 14062306a36Sopenharmony_ci struct nl4_server *nss = NULL; 14162306a36Sopenharmony_ci nfs4_stateid *cnrs = NULL; 14262306a36Sopenharmony_ci ssize_t ret; 14362306a36Sopenharmony_ci bool sync = false; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* Only offload copy if superblock is the same */ 14662306a36Sopenharmony_ci if (file_in->f_op != &nfs4_file_operations) 14762306a36Sopenharmony_ci return -EXDEV; 14862306a36Sopenharmony_ci if (!nfs_server_capable(file_inode(file_out), NFS_CAP_COPY) || 14962306a36Sopenharmony_ci !nfs_server_capable(file_inode(file_in), NFS_CAP_COPY)) 15062306a36Sopenharmony_ci return -EOPNOTSUPP; 15162306a36Sopenharmony_ci if (file_inode(file_in) == file_inode(file_out)) 15262306a36Sopenharmony_ci return -EOPNOTSUPP; 15362306a36Sopenharmony_ci /* if the copy size if smaller than 2 RPC payloads, make it 15462306a36Sopenharmony_ci * synchronous 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci if (count <= 2 * NFS_SERVER(file_inode(file_in))->rsize) 15762306a36Sopenharmony_ci sync = true; 15862306a36Sopenharmony_ciretry: 15962306a36Sopenharmony_ci if (!nfs42_files_from_same_server(file_in, file_out)) { 16062306a36Sopenharmony_ci /* 16162306a36Sopenharmony_ci * for inter copy, if copy size is too small 16262306a36Sopenharmony_ci * then fallback to generic copy. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci if (sync) 16562306a36Sopenharmony_ci return -EOPNOTSUPP; 16662306a36Sopenharmony_ci cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res), 16762306a36Sopenharmony_ci GFP_KERNEL); 16862306a36Sopenharmony_ci if (unlikely(cn_resp == NULL)) 16962306a36Sopenharmony_ci return -ENOMEM; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci ret = nfs42_proc_copy_notify(file_in, file_out, cn_resp); 17262306a36Sopenharmony_ci if (ret) { 17362306a36Sopenharmony_ci ret = -EOPNOTSUPP; 17462306a36Sopenharmony_ci goto out; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci nss = &cn_resp->cnr_src; 17762306a36Sopenharmony_ci cnrs = &cn_resp->cnr_stateid; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count, 18062306a36Sopenharmony_ci nss, cnrs, sync); 18162306a36Sopenharmony_ciout: 18262306a36Sopenharmony_ci kfree(cn_resp); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (ret == -EAGAIN) 18562306a36Sopenharmony_ci goto retry; 18662306a36Sopenharmony_ci return ret; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in, 19062306a36Sopenharmony_ci struct file *file_out, loff_t pos_out, 19162306a36Sopenharmony_ci size_t count, unsigned int flags) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci ssize_t ret; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci ret = __nfs4_copy_file_range(file_in, pos_in, file_out, pos_out, count, 19662306a36Sopenharmony_ci flags); 19762306a36Sopenharmony_ci if (ret == -EOPNOTSUPP || ret == -EXDEV) 19862306a36Sopenharmony_ci ret = generic_copy_file_range(file_in, pos_in, file_out, 19962306a36Sopenharmony_ci pos_out, count, flags); 20062306a36Sopenharmony_ci return ret; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci loff_t ret; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci switch (whence) { 20862306a36Sopenharmony_ci case SEEK_HOLE: 20962306a36Sopenharmony_ci case SEEK_DATA: 21062306a36Sopenharmony_ci ret = nfs42_proc_llseek(filep, offset, whence); 21162306a36Sopenharmony_ci if (ret != -EOPNOTSUPP) 21262306a36Sopenharmony_ci return ret; 21362306a36Sopenharmony_ci fallthrough; 21462306a36Sopenharmony_ci default: 21562306a36Sopenharmony_ci return nfs_file_llseek(filep, offset, whence); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t len) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct inode *inode = file_inode(filep); 22262306a36Sopenharmony_ci long ret; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (!S_ISREG(inode->i_mode)) 22562306a36Sopenharmony_ci return -EOPNOTSUPP; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if ((mode != 0) && (mode != (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE))) 22862306a36Sopenharmony_ci return -EOPNOTSUPP; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci ret = inode_newsize_ok(inode, offset + len); 23162306a36Sopenharmony_ci if (ret < 0) 23262306a36Sopenharmony_ci return ret; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (mode & FALLOC_FL_PUNCH_HOLE) 23562306a36Sopenharmony_ci return nfs42_proc_deallocate(filep, offset, len); 23662306a36Sopenharmony_ci return nfs42_proc_allocate(filep, offset, len); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off, 24062306a36Sopenharmony_ci struct file *dst_file, loff_t dst_off, loff_t count, 24162306a36Sopenharmony_ci unsigned int remap_flags) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct inode *dst_inode = file_inode(dst_file); 24462306a36Sopenharmony_ci struct nfs_server *server = NFS_SERVER(dst_inode); 24562306a36Sopenharmony_ci struct inode *src_inode = file_inode(src_file); 24662306a36Sopenharmony_ci unsigned int bs = server->clone_blksize; 24762306a36Sopenharmony_ci bool same_inode = false; 24862306a36Sopenharmony_ci int ret; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* NFS does not support deduplication. */ 25162306a36Sopenharmony_ci if (remap_flags & REMAP_FILE_DEDUP) 25262306a36Sopenharmony_ci return -EOPNOTSUPP; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (remap_flags & ~REMAP_FILE_ADVISORY) 25562306a36Sopenharmony_ci return -EINVAL; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (IS_SWAPFILE(dst_inode) || IS_SWAPFILE(src_inode)) 25862306a36Sopenharmony_ci return -ETXTBSY; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* check alignment w.r.t. clone_blksize */ 26162306a36Sopenharmony_ci ret = -EINVAL; 26262306a36Sopenharmony_ci if (bs) { 26362306a36Sopenharmony_ci if (!IS_ALIGNED(src_off, bs) || !IS_ALIGNED(dst_off, bs)) 26462306a36Sopenharmony_ci goto out; 26562306a36Sopenharmony_ci if (!IS_ALIGNED(count, bs) && i_size_read(src_inode) != (src_off + count)) 26662306a36Sopenharmony_ci goto out; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (src_inode == dst_inode) 27062306a36Sopenharmony_ci same_inode = true; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */ 27362306a36Sopenharmony_ci if (same_inode) { 27462306a36Sopenharmony_ci inode_lock(src_inode); 27562306a36Sopenharmony_ci } else if (dst_inode < src_inode) { 27662306a36Sopenharmony_ci inode_lock_nested(dst_inode, I_MUTEX_PARENT); 27762306a36Sopenharmony_ci inode_lock_nested(src_inode, I_MUTEX_CHILD); 27862306a36Sopenharmony_ci } else { 27962306a36Sopenharmony_ci inode_lock_nested(src_inode, I_MUTEX_PARENT); 28062306a36Sopenharmony_ci inode_lock_nested(dst_inode, I_MUTEX_CHILD); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* flush all pending writes on both src and dst so that server 28462306a36Sopenharmony_ci * has the latest data */ 28562306a36Sopenharmony_ci ret = nfs_sync_inode(src_inode); 28662306a36Sopenharmony_ci if (ret) 28762306a36Sopenharmony_ci goto out_unlock; 28862306a36Sopenharmony_ci ret = nfs_sync_inode(dst_inode); 28962306a36Sopenharmony_ci if (ret) 29062306a36Sopenharmony_ci goto out_unlock; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci ret = nfs42_proc_clone(src_file, dst_file, src_off, dst_off, count); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* truncate inode page cache of the dst range so that future reads can fetch 29562306a36Sopenharmony_ci * new data from server */ 29662306a36Sopenharmony_ci if (!ret) 29762306a36Sopenharmony_ci truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ciout_unlock: 30062306a36Sopenharmony_ci if (same_inode) { 30162306a36Sopenharmony_ci inode_unlock(src_inode); 30262306a36Sopenharmony_ci } else if (dst_inode < src_inode) { 30362306a36Sopenharmony_ci inode_unlock(src_inode); 30462306a36Sopenharmony_ci inode_unlock(dst_inode); 30562306a36Sopenharmony_ci } else { 30662306a36Sopenharmony_ci inode_unlock(dst_inode); 30762306a36Sopenharmony_ci inode_unlock(src_inode); 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ciout: 31062306a36Sopenharmony_ci return ret < 0 ? ret : count; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int read_name_gen = 1; 31462306a36Sopenharmony_ci#define SSC_READ_NAME_BODY "ssc_read_%d" 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic struct file *__nfs42_ssc_open(struct vfsmount *ss_mnt, 31762306a36Sopenharmony_ci struct nfs_fh *src_fh, nfs4_stateid *stateid) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct nfs_fattr *fattr = nfs_alloc_fattr(); 32062306a36Sopenharmony_ci struct file *filep, *res; 32162306a36Sopenharmony_ci struct nfs_server *server; 32262306a36Sopenharmony_ci struct inode *r_ino = NULL; 32362306a36Sopenharmony_ci struct nfs_open_context *ctx; 32462306a36Sopenharmony_ci struct nfs4_state_owner *sp; 32562306a36Sopenharmony_ci char *read_name = NULL; 32662306a36Sopenharmony_ci int len, status = 0; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci server = NFS_SB(ss_mnt->mnt_sb); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (!fattr) 33162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci status = nfs4_proc_getattr(server, src_fh, fattr, NULL); 33462306a36Sopenharmony_ci if (status < 0) { 33562306a36Sopenharmony_ci res = ERR_PTR(status); 33662306a36Sopenharmony_ci goto out; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (!S_ISREG(fattr->mode)) { 34062306a36Sopenharmony_ci res = ERR_PTR(-EBADF); 34162306a36Sopenharmony_ci goto out; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci res = ERR_PTR(-ENOMEM); 34562306a36Sopenharmony_ci len = strlen(SSC_READ_NAME_BODY) + 16; 34662306a36Sopenharmony_ci read_name = kzalloc(len, GFP_KERNEL); 34762306a36Sopenharmony_ci if (read_name == NULL) 34862306a36Sopenharmony_ci goto out; 34962306a36Sopenharmony_ci snprintf(read_name, len, SSC_READ_NAME_BODY, read_name_gen++); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci r_ino = nfs_fhget(ss_mnt->mnt_sb, src_fh, fattr); 35262306a36Sopenharmony_ci if (IS_ERR(r_ino)) { 35362306a36Sopenharmony_ci res = ERR_CAST(r_ino); 35462306a36Sopenharmony_ci goto out_free_name; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci filep = alloc_file_pseudo(r_ino, ss_mnt, read_name, O_RDONLY, 35862306a36Sopenharmony_ci r_ino->i_fop); 35962306a36Sopenharmony_ci if (IS_ERR(filep)) { 36062306a36Sopenharmony_ci res = ERR_CAST(filep); 36162306a36Sopenharmony_ci iput(r_ino); 36262306a36Sopenharmony_ci goto out_free_name; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci ctx = alloc_nfs_open_context(filep->f_path.dentry, 36662306a36Sopenharmony_ci flags_to_mode(filep->f_flags), filep); 36762306a36Sopenharmony_ci if (IS_ERR(ctx)) { 36862306a36Sopenharmony_ci res = ERR_CAST(ctx); 36962306a36Sopenharmony_ci goto out_filep; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci res = ERR_PTR(-EINVAL); 37362306a36Sopenharmony_ci sp = nfs4_get_state_owner(server, ctx->cred, GFP_KERNEL); 37462306a36Sopenharmony_ci if (sp == NULL) 37562306a36Sopenharmony_ci goto out_ctx; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci ctx->state = nfs4_get_open_state(r_ino, sp); 37862306a36Sopenharmony_ci if (ctx->state == NULL) 37962306a36Sopenharmony_ci goto out_stateowner; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci set_bit(NFS_SRV_SSC_COPY_STATE, &ctx->state->flags); 38262306a36Sopenharmony_ci memcpy(&ctx->state->open_stateid.other, &stateid->other, 38362306a36Sopenharmony_ci NFS4_STATEID_OTHER_SIZE); 38462306a36Sopenharmony_ci update_open_stateid(ctx->state, stateid, NULL, filep->f_mode); 38562306a36Sopenharmony_ci set_bit(NFS_OPEN_STATE, &ctx->state->flags); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci nfs_file_set_open_context(filep, ctx); 38862306a36Sopenharmony_ci put_nfs_open_context(ctx); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci file_ra_state_init(&filep->f_ra, filep->f_mapping->host->i_mapping); 39162306a36Sopenharmony_ci res = filep; 39262306a36Sopenharmony_ciout_free_name: 39362306a36Sopenharmony_ci kfree(read_name); 39462306a36Sopenharmony_ciout: 39562306a36Sopenharmony_ci nfs_free_fattr(fattr); 39662306a36Sopenharmony_ci return res; 39762306a36Sopenharmony_ciout_stateowner: 39862306a36Sopenharmony_ci nfs4_put_state_owner(sp); 39962306a36Sopenharmony_ciout_ctx: 40062306a36Sopenharmony_ci put_nfs_open_context(ctx); 40162306a36Sopenharmony_ciout_filep: 40262306a36Sopenharmony_ci fput(filep); 40362306a36Sopenharmony_ci goto out_free_name; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic void __nfs42_ssc_close(struct file *filep) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct nfs_open_context *ctx = nfs_file_open_context(filep); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci ctx->state->flags = 0; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic const struct nfs4_ssc_client_ops nfs4_ssc_clnt_ops_tbl = { 41462306a36Sopenharmony_ci .sco_open = __nfs42_ssc_open, 41562306a36Sopenharmony_ci .sco_close = __nfs42_ssc_close, 41662306a36Sopenharmony_ci}; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/** 41962306a36Sopenharmony_ci * nfs42_ssc_register_ops - Wrapper to register NFS_V4 ops in nfs_common 42062306a36Sopenharmony_ci * 42162306a36Sopenharmony_ci * Return values: 42262306a36Sopenharmony_ci * None 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_civoid nfs42_ssc_register_ops(void) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci nfs42_ssc_register(&nfs4_ssc_clnt_ops_tbl); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/** 43062306a36Sopenharmony_ci * nfs42_ssc_unregister_ops - wrapper to un-register NFS_V4 ops in nfs_common 43162306a36Sopenharmony_ci * 43262306a36Sopenharmony_ci * Return values: 43362306a36Sopenharmony_ci * None. 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_civoid nfs42_ssc_unregister_ops(void) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci nfs42_ssc_unregister(&nfs4_ssc_clnt_ops_tbl); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci#endif /* CONFIG_NFS_V4_2 */ 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic int nfs4_setlease(struct file *file, int arg, struct file_lock **lease, 44262306a36Sopenharmony_ci void **priv) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci return nfs4_proc_setlease(file, arg, lease, priv); 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ciconst struct file_operations nfs4_file_operations = { 44862306a36Sopenharmony_ci .read_iter = nfs_file_read, 44962306a36Sopenharmony_ci .write_iter = nfs_file_write, 45062306a36Sopenharmony_ci .mmap = nfs_file_mmap, 45162306a36Sopenharmony_ci .open = nfs4_file_open, 45262306a36Sopenharmony_ci .flush = nfs4_file_flush, 45362306a36Sopenharmony_ci .release = nfs_file_release, 45462306a36Sopenharmony_ci .fsync = nfs_file_fsync, 45562306a36Sopenharmony_ci .lock = nfs_lock, 45662306a36Sopenharmony_ci .flock = nfs_flock, 45762306a36Sopenharmony_ci .splice_read = nfs_file_splice_read, 45862306a36Sopenharmony_ci .splice_write = iter_file_splice_write, 45962306a36Sopenharmony_ci .check_flags = nfs_check_flags, 46062306a36Sopenharmony_ci .setlease = nfs4_setlease, 46162306a36Sopenharmony_ci#ifdef CONFIG_NFS_V4_2 46262306a36Sopenharmony_ci .copy_file_range = nfs4_copy_file_range, 46362306a36Sopenharmony_ci .llseek = nfs4_file_llseek, 46462306a36Sopenharmony_ci .fallocate = nfs42_fallocate, 46562306a36Sopenharmony_ci .remap_file_range = nfs42_remap_file_range, 46662306a36Sopenharmony_ci#else 46762306a36Sopenharmony_ci .llseek = nfs_file_llseek, 46862306a36Sopenharmony_ci#endif 46962306a36Sopenharmony_ci}; 470