1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2ce4ef7c0SBryan Schumaker /*
3ce4ef7c0SBryan Schumaker * linux/fs/nfs/file.c
4ce4ef7c0SBryan Schumaker *
5ce4ef7c0SBryan Schumaker * Copyright (C) 1992 Rick Sladkey
6ce4ef7c0SBryan Schumaker */
7f4ac1674SAnna Schumaker #include <linux/fs.h>
8bea51b30SPeng Tao #include <linux/file.h>
9f4ac1674SAnna Schumaker #include <linux/falloc.h>
10f2aedb71SDavid Howells #include <linux/mount.h>
11ce4ef7c0SBryan Schumaker #include <linux/nfs_fs.h>
120cfcd405SDai Ngo #include <linux/nfs_ssc.h>
135445b1fbSTrond Myklebust #include "delegation.h"
14ce4ef7c0SBryan Schumaker #include "internal.h"
155445b1fbSTrond Myklebust #include "iostat.h"
16a4ff1468SDavid Howells #include "fscache.h"
17ce4ef7c0SBryan Schumaker #include "pnfs.h"
18ce4ef7c0SBryan Schumaker
1981b79afbSTrond Myklebust #include "nfstrace.h"
2081b79afbSTrond Myklebust
211c6dcbe5SAnna Schumaker #ifdef CONFIG_NFS_V4_2
221c6dcbe5SAnna Schumaker #include "nfs42.h"
231c6dcbe5SAnna Schumaker #endif
241c6dcbe5SAnna Schumaker
25ce4ef7c0SBryan Schumaker #define NFSDBG_FACILITY NFSDBG_FILE
26ce4ef7c0SBryan Schumaker
27ce4ef7c0SBryan Schumaker static int
nfs4_file_open(struct inode * inode,struct file * filp)28ce4ef7c0SBryan Schumaker nfs4_file_open(struct inode *inode, struct file *filp)
29ce4ef7c0SBryan Schumaker {
30ce4ef7c0SBryan Schumaker struct nfs_open_context *ctx;
31be62a1a8SMiklos Szeredi struct dentry *dentry = file_dentry(filp);
32ce4ef7c0SBryan Schumaker struct dentry *parent = NULL;
33ce4ef7c0SBryan Schumaker struct inode *dir;
34ce4ef7c0SBryan Schumaker unsigned openflags = filp->f_flags;
35ce4ef7c0SBryan Schumaker struct iattr attr;
36ce4ef7c0SBryan Schumaker int err;
37ce4ef7c0SBryan Schumaker
38ce4ef7c0SBryan Schumaker /*
39ce4ef7c0SBryan Schumaker * If no cached dentry exists or if it's negative, NFSv4 handled the
40ce4ef7c0SBryan Schumaker * opens in ->lookup() or ->create().
41ce4ef7c0SBryan Schumaker *
42ce4ef7c0SBryan Schumaker * We only get this far for a cached positive dentry. We skipped
43ce4ef7c0SBryan Schumaker * revalidation, so handle it here by dropping the dentry and returning
44ce4ef7c0SBryan Schumaker * -EOPENSTALE. The VFS will retry the lookup/create/open.
45ce4ef7c0SBryan Schumaker */
46ce4ef7c0SBryan Schumaker
476de1472fSAl Viro dprintk("NFS: open file(%pd2)\n", dentry);
48ce4ef7c0SBryan Schumaker
4918a60089SBenjamin Coddington err = nfs_check_flags(openflags);
5018a60089SBenjamin Coddington if (err)
5118a60089SBenjamin Coddington return err;
5218a60089SBenjamin Coddington
53ce4ef7c0SBryan Schumaker /* We can't create new files here */
54ce4ef7c0SBryan Schumaker openflags &= ~(O_CREAT|O_EXCL);
55ce4ef7c0SBryan Schumaker
56ce4ef7c0SBryan Schumaker parent = dget_parent(dentry);
572b0143b5SDavid Howells dir = d_inode(parent);
58ce4ef7c0SBryan Schumaker
596f1c1d95SChenXiaoSong ctx = alloc_nfs_open_context(file_dentry(filp),
606f1c1d95SChenXiaoSong flags_to_mode(openflags), filp);
61ce4ef7c0SBryan Schumaker err = PTR_ERR(ctx);
62ce4ef7c0SBryan Schumaker if (IS_ERR(ctx))
63ce4ef7c0SBryan Schumaker goto out;
64ce4ef7c0SBryan Schumaker
65ce4ef7c0SBryan Schumaker attr.ia_valid = ATTR_OPEN;
66ce4ef7c0SBryan Schumaker if (openflags & O_TRUNC) {
67ce4ef7c0SBryan Schumaker attr.ia_valid |= ATTR_SIZE;
68ce4ef7c0SBryan Schumaker attr.ia_size = 0;
698b7d9d09STrond Myklebust filemap_write_and_wait(inode->i_mapping);
70ce4ef7c0SBryan Schumaker }
71ce4ef7c0SBryan Schumaker
72c5c3fb5fSKinglong Mee inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, NULL);
73ce4ef7c0SBryan Schumaker if (IS_ERR(inode)) {
74ce4ef7c0SBryan Schumaker err = PTR_ERR(inode);
75ce4ef7c0SBryan Schumaker switch (err) {
76ce4ef7c0SBryan Schumaker default:
7790cf500eSTrond Myklebust goto out_put_ctx;
7890cf500eSTrond Myklebust case -ENOENT:
7990cf500eSTrond Myklebust case -ESTALE:
8090cf500eSTrond Myklebust case -EISDIR:
8190cf500eSTrond Myklebust case -ENOTDIR:
8290cf500eSTrond Myklebust case -ELOOP:
83ce4ef7c0SBryan Schumaker goto out_drop;
84ce4ef7c0SBryan Schumaker }
85ce4ef7c0SBryan Schumaker }
862b0143b5SDavid Howells if (inode != d_inode(dentry))
87ce4ef7c0SBryan Schumaker goto out_drop;
88ce4ef7c0SBryan Schumaker
89ce4ef7c0SBryan Schumaker nfs_file_set_open_context(filp, ctx);
90f1fe29b4SDavid Howells nfs_fscache_open_file(inode, filp);
91ce4ef7c0SBryan Schumaker err = 0;
925ee3d10fSDave Wysochanski filp->f_mode |= FMODE_CAN_ODIRECT;
93ce4ef7c0SBryan Schumaker
94ce4ef7c0SBryan Schumaker out_put_ctx:
95ce4ef7c0SBryan Schumaker put_nfs_open_context(ctx);
96ce4ef7c0SBryan Schumaker out:
97ce4ef7c0SBryan Schumaker dput(parent);
98ce4ef7c0SBryan Schumaker return err;
99ce4ef7c0SBryan Schumaker
100ce4ef7c0SBryan Schumaker out_drop:
101ce4ef7c0SBryan Schumaker d_drop(dentry);
102ce4ef7c0SBryan Schumaker err = -EOPENSTALE;
103ce4ef7c0SBryan Schumaker goto out_put_ctx;
104ce4ef7c0SBryan Schumaker }
105ce4ef7c0SBryan Schumaker
1065445b1fbSTrond Myklebust /*
1075445b1fbSTrond Myklebust * Flush all dirty pages, and check for write errors.
1085445b1fbSTrond Myklebust */
1095445b1fbSTrond Myklebust static int
nfs4_file_flush(struct file * file,fl_owner_t id)1105445b1fbSTrond Myklebust nfs4_file_flush(struct file *file, fl_owner_t id)
1115445b1fbSTrond Myklebust {
1125445b1fbSTrond Myklebust struct inode *inode = file_inode(file);
11367dd23f9SScott Mayhew errseq_t since;
1145445b1fbSTrond Myklebust
1155445b1fbSTrond Myklebust dprintk("NFS: flush(%pD2)\n", file);
1165445b1fbSTrond Myklebust
1175445b1fbSTrond Myklebust nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
1185445b1fbSTrond Myklebust if ((file->f_mode & FMODE_WRITE) == 0)
1195445b1fbSTrond Myklebust return 0;
1205445b1fbSTrond Myklebust
1215445b1fbSTrond Myklebust /*
1225445b1fbSTrond Myklebust * If we're holding a write delegation, then check if we're required
1235445b1fbSTrond Myklebust * to flush the i/o on close. If not, then just start the i/o now.
1245445b1fbSTrond Myklebust */
1255445b1fbSTrond Myklebust if (!nfs4_delegation_flush_on_close(inode))
1265445b1fbSTrond Myklebust return filemap_fdatawrite(file->f_mapping);
1275445b1fbSTrond Myklebust
1285445b1fbSTrond Myklebust /* Flush writes to the server and return any errors */
12967dd23f9SScott Mayhew since = filemap_sample_wb_err(file->f_mapping);
13067dd23f9SScott Mayhew nfs_wb_all(inode);
13167dd23f9SScott Mayhew return filemap_check_wb_err(file->f_mapping, since);
1325445b1fbSTrond Myklebust }
1335445b1fbSTrond Myklebust
1341c6dcbe5SAnna Schumaker #ifdef CONFIG_NFS_V4_2
__nfs4_copy_file_range(struct file * file_in,loff_t pos_in,struct file * file_out,loff_t pos_out,size_t count,unsigned int flags)13564bf5ff5SDave Chinner static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
1362e72448bSAnna Schumaker struct file *file_out, loff_t pos_out,
1372e72448bSAnna Schumaker size_t count, unsigned int flags)
1382e72448bSAnna Schumaker {
1390491567bSOlga Kornievskaia struct nfs42_copy_notify_res *cn_resp = NULL;
1401d38f3f0SOlga Kornievskaia struct nl4_server *nss = NULL;
1411d38f3f0SOlga Kornievskaia nfs4_stateid *cnrs = NULL;
1420491567bSOlga Kornievskaia ssize_t ret;
14312751010SOlga Kornievskaia bool sync = false;
1440491567bSOlga Kornievskaia
1455dae222aSAmir Goldstein /* Only offload copy if superblock is the same */
1468dff1df5SOlga Kornievskaia if (file_in->f_op != &nfs4_file_operations)
1475dae222aSAmir Goldstein return -EXDEV;
148d8a6ad91SDave Wysochanski if (!nfs_server_capable(file_inode(file_out), NFS_CAP_COPY) ||
149d8a6ad91SDave Wysochanski !nfs_server_capable(file_inode(file_in), NFS_CAP_COPY))
1500769663bSOlga Kornievskaia return -EOPNOTSUPP;
151837bb1d7STrond Myklebust if (file_inode(file_in) == file_inode(file_out))
1520769663bSOlga Kornievskaia return -EOPNOTSUPP;
15312751010SOlga Kornievskaia /* if the copy size if smaller than 2 RPC payloads, make it
15412751010SOlga Kornievskaia * synchronous
15512751010SOlga Kornievskaia */
15612751010SOlga Kornievskaia if (count <= 2 * NFS_SERVER(file_inode(file_in))->rsize)
15712751010SOlga Kornievskaia sync = true;
1580e65a32cSOlga Kornievskaia retry:
1590491567bSOlga Kornievskaia if (!nfs42_files_from_same_server(file_in, file_out)) {
160ca7d1d1aSDai Ngo /*
161ca7d1d1aSDai Ngo * for inter copy, if copy size is too small
162ca7d1d1aSDai Ngo * then fallback to generic copy.
16312751010SOlga Kornievskaia */
164ca7d1d1aSDai Ngo if (sync)
16512751010SOlga Kornievskaia return -EOPNOTSUPP;
1660491567bSOlga Kornievskaia cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
1674fb547beSTrond Myklebust GFP_KERNEL);
1680491567bSOlga Kornievskaia if (unlikely(cn_resp == NULL))
1690491567bSOlga Kornievskaia return -ENOMEM;
1700491567bSOlga Kornievskaia
1710491567bSOlga Kornievskaia ret = nfs42_proc_copy_notify(file_in, file_out, cn_resp);
1720491567bSOlga Kornievskaia if (ret) {
1730491567bSOlga Kornievskaia ret = -EOPNOTSUPP;
1740491567bSOlga Kornievskaia goto out;
1750491567bSOlga Kornievskaia }
1761d38f3f0SOlga Kornievskaia nss = &cn_resp->cnr_src;
1771d38f3f0SOlga Kornievskaia cnrs = &cn_resp->cnr_stateid;
1780491567bSOlga Kornievskaia }
1791d38f3f0SOlga Kornievskaia ret = nfs42_proc_copy(file_in, pos_in, file_out, pos_out, count,
18012751010SOlga Kornievskaia nss, cnrs, sync);
1810491567bSOlga Kornievskaia out:
1820491567bSOlga Kornievskaia kfree(cn_resp);
18398c27f27STom Rix
1840e65a32cSOlga Kornievskaia if (ret == -EAGAIN)
1850e65a32cSOlga Kornievskaia goto retry;
1860491567bSOlga Kornievskaia return ret;
1872e72448bSAnna Schumaker }
1882e72448bSAnna Schumaker
nfs4_copy_file_range(struct file * file_in,loff_t pos_in,struct file * file_out,loff_t pos_out,size_t count,unsigned int flags)18964bf5ff5SDave Chinner static ssize_t nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
19064bf5ff5SDave Chinner struct file *file_out, loff_t pos_out,
19164bf5ff5SDave Chinner size_t count, unsigned int flags)
19264bf5ff5SDave Chinner {
19364bf5ff5SDave Chinner ssize_t ret;
19464bf5ff5SDave Chinner
19564bf5ff5SDave Chinner ret = __nfs4_copy_file_range(file_in, pos_in, file_out, pos_out, count,
19664bf5ff5SDave Chinner flags);
1975dae222aSAmir Goldstein if (ret == -EOPNOTSUPP || ret == -EXDEV)
19864bf5ff5SDave Chinner ret = generic_copy_file_range(file_in, pos_in, file_out,
19964bf5ff5SDave Chinner pos_out, count, flags);
20064bf5ff5SDave Chinner return ret;
20164bf5ff5SDave Chinner }
20264bf5ff5SDave Chinner
nfs4_file_llseek(struct file * filep,loff_t offset,int whence)2031c6dcbe5SAnna Schumaker static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
2041c6dcbe5SAnna Schumaker {
2051c6dcbe5SAnna Schumaker loff_t ret;
2061c6dcbe5SAnna Schumaker
2071c6dcbe5SAnna Schumaker switch (whence) {
2081c6dcbe5SAnna Schumaker case SEEK_HOLE:
2091c6dcbe5SAnna Schumaker case SEEK_DATA:
2101c6dcbe5SAnna Schumaker ret = nfs42_proc_llseek(filep, offset, whence);
211e67afa7eSZhang Xiaoxu if (ret != -EOPNOTSUPP)
2121c6dcbe5SAnna Schumaker return ret;
213df561f66SGustavo A. R. Silva fallthrough;
2141c6dcbe5SAnna Schumaker default:
2151c6dcbe5SAnna Schumaker return nfs_file_llseek(filep, offset, whence);
2161c6dcbe5SAnna Schumaker }
2171c6dcbe5SAnna Schumaker }
218f4ac1674SAnna Schumaker
nfs42_fallocate(struct file * filep,int mode,loff_t offset,loff_t len)219f4ac1674SAnna Schumaker static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t len)
220f4ac1674SAnna Schumaker {
221f4ac1674SAnna Schumaker struct inode *inode = file_inode(filep);
222f4ac1674SAnna Schumaker long ret;
223f4ac1674SAnna Schumaker
224f4ac1674SAnna Schumaker if (!S_ISREG(inode->i_mode))
225f4ac1674SAnna Schumaker return -EOPNOTSUPP;
226f4ac1674SAnna Schumaker
227624bd5b7SAnna Schumaker if ((mode != 0) && (mode != (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)))
228f4ac1674SAnna Schumaker return -EOPNOTSUPP;
229f4ac1674SAnna Schumaker
230f4ac1674SAnna Schumaker ret = inode_newsize_ok(inode, offset + len);
231f4ac1674SAnna Schumaker if (ret < 0)
232f4ac1674SAnna Schumaker return ret;
233f4ac1674SAnna Schumaker
234624bd5b7SAnna Schumaker if (mode & FALLOC_FL_PUNCH_HOLE)
235f830f7ddSAnna Schumaker return nfs42_proc_deallocate(filep, offset, len);
236f830f7ddSAnna Schumaker return nfs42_proc_allocate(filep, offset, len);
237f4ac1674SAnna Schumaker }
238bea51b30SPeng Tao
nfs42_remap_file_range(struct file * src_file,loff_t src_off,struct file * dst_file,loff_t dst_off,loff_t count,unsigned int remap_flags)23942ec3d4cSDarrick J. Wong static loff_t nfs42_remap_file_range(struct file *src_file, loff_t src_off,
24042ec3d4cSDarrick J. Wong struct file *dst_file, loff_t dst_off, loff_t count,
2412e5dfc99SDarrick J. Wong unsigned int remap_flags)
242bea51b30SPeng Tao {
243bea51b30SPeng Tao struct inode *dst_inode = file_inode(dst_file);
244811b7b85SPeng Tao struct nfs_server *server = NFS_SERVER(dst_inode);
24504b38d60SChristoph Hellwig struct inode *src_inode = file_inode(src_file);
246811b7b85SPeng Tao unsigned int bs = server->clone_blksize;
24721fad313SChristoph Hellwig bool same_inode = false;
248bea51b30SPeng Tao int ret;
249bea51b30SPeng Tao
2509026b3a9SDarrick J. Wong /* NFS does not support deduplication. */
2519026b3a9SDarrick J. Wong if (remap_flags & REMAP_FILE_DEDUP)
2529026b3a9SDarrick J. Wong return -EOPNOTSUPP;
2539026b3a9SDarrick J. Wong
2549026b3a9SDarrick J. Wong if (remap_flags & ~REMAP_FILE_ADVISORY)
2552e5dfc99SDarrick J. Wong return -EINVAL;
2562e5dfc99SDarrick J. Wong
257f5fdf124SMurphy Zhou if (IS_SWAPFILE(dst_inode) || IS_SWAPFILE(src_inode))
258f5fdf124SMurphy Zhou return -ETXTBSY;
259f5fdf124SMurphy Zhou
260811b7b85SPeng Tao /* check alignment w.r.t. clone_blksize */
261811b7b85SPeng Tao ret = -EINVAL;
262811b7b85SPeng Tao if (bs) {
263811b7b85SPeng Tao if (!IS_ALIGNED(src_off, bs) || !IS_ALIGNED(dst_off, bs))
26404b38d60SChristoph Hellwig goto out;
265811b7b85SPeng Tao if (!IS_ALIGNED(count, bs) && i_size_read(src_inode) != (src_off + count))
26604b38d60SChristoph Hellwig goto out;
267811b7b85SPeng Tao }
268811b7b85SPeng Tao
26904b38d60SChristoph Hellwig if (src_inode == dst_inode)
27004b38d60SChristoph Hellwig same_inode = true;
27121fad313SChristoph Hellwig
272bea51b30SPeng Tao /* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */
27321fad313SChristoph Hellwig if (same_inode) {
2745955102cSAl Viro inode_lock(src_inode);
27521fad313SChristoph Hellwig } else if (dst_inode < src_inode) {
2765955102cSAl Viro inode_lock_nested(dst_inode, I_MUTEX_PARENT);
2775955102cSAl Viro inode_lock_nested(src_inode, I_MUTEX_CHILD);
278bea51b30SPeng Tao } else {
2795955102cSAl Viro inode_lock_nested(src_inode, I_MUTEX_PARENT);
2805955102cSAl Viro inode_lock_nested(dst_inode, I_MUTEX_CHILD);
281bea51b30SPeng Tao }
282bea51b30SPeng Tao
283bea51b30SPeng Tao /* flush all pending writes on both src and dst so that server
284bea51b30SPeng Tao * has the latest data */
285bea51b30SPeng Tao ret = nfs_sync_inode(src_inode);
286bea51b30SPeng Tao if (ret)
287bea51b30SPeng Tao goto out_unlock;
288bea51b30SPeng Tao ret = nfs_sync_inode(dst_inode);
289bea51b30SPeng Tao if (ret)
290bea51b30SPeng Tao goto out_unlock;
291bea51b30SPeng Tao
29204b38d60SChristoph Hellwig ret = nfs42_proc_clone(src_file, dst_file, src_off, dst_off, count);
293bea51b30SPeng Tao
294bea51b30SPeng Tao /* truncate inode page cache of the dst range so that future reads can fetch
295bea51b30SPeng Tao * new data from server */
296bea51b30SPeng Tao if (!ret)
297bea51b30SPeng Tao truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1);
298bea51b30SPeng Tao
299bea51b30SPeng Tao out_unlock:
30021fad313SChristoph Hellwig if (same_inode) {
3015955102cSAl Viro inode_unlock(src_inode);
30221fad313SChristoph Hellwig } else if (dst_inode < src_inode) {
3035955102cSAl Viro inode_unlock(src_inode);
3045955102cSAl Viro inode_unlock(dst_inode);
305bea51b30SPeng Tao } else {
3065955102cSAl Viro inode_unlock(dst_inode);
3075955102cSAl Viro inode_unlock(src_inode);
308bea51b30SPeng Tao }
30904b38d60SChristoph Hellwig out:
31042ec3d4cSDarrick J. Wong return ret < 0 ? ret : count;
311bea51b30SPeng Tao }
312ec4b0925SOlga Kornievskaia
313ec4b0925SOlga Kornievskaia static int read_name_gen = 1;
314ec4b0925SOlga Kornievskaia #define SSC_READ_NAME_BODY "ssc_read_%d"
315ec4b0925SOlga Kornievskaia
__nfs42_ssc_open(struct vfsmount * ss_mnt,struct nfs_fh * src_fh,nfs4_stateid * stateid)3160cfcd405SDai Ngo static struct file *__nfs42_ssc_open(struct vfsmount *ss_mnt,
3170cfcd405SDai Ngo struct nfs_fh *src_fh, nfs4_stateid *stateid)
318ec4b0925SOlga Kornievskaia {
319156cd285STrond Myklebust struct nfs_fattr *fattr = nfs_alloc_fattr();
320ec4b0925SOlga Kornievskaia struct file *filep, *res;
321ec4b0925SOlga Kornievskaia struct nfs_server *server;
322ec4b0925SOlga Kornievskaia struct inode *r_ino = NULL;
323ec4b0925SOlga Kornievskaia struct nfs_open_context *ctx;
324ec4b0925SOlga Kornievskaia struct nfs4_state_owner *sp;
325f751c545SOlga Kornievskaia char *read_name = NULL;
326ec4b0925SOlga Kornievskaia int len, status = 0;
327ec4b0925SOlga Kornievskaia
328f6957b71SAl Viro server = NFS_SB(ss_mnt->mnt_sb);
329ec4b0925SOlga Kornievskaia
330156cd285STrond Myklebust if (!fattr)
331156cd285STrond Myklebust return ERR_PTR(-ENOMEM);
332ec4b0925SOlga Kornievskaia
3332ef61e0eSAnna Schumaker status = nfs4_proc_getattr(server, src_fh, fattr, NULL);
334ec4b0925SOlga Kornievskaia if (status < 0) {
335ec4b0925SOlga Kornievskaia res = ERR_PTR(status);
336ec4b0925SOlga Kornievskaia goto out;
337ec4b0925SOlga Kornievskaia }
338ec4b0925SOlga Kornievskaia
339fcfc8be1SOlga Kornievskaia if (!S_ISREG(fattr->mode)) {
340fcfc8be1SOlga Kornievskaia res = ERR_PTR(-EBADF);
341fcfc8be1SOlga Kornievskaia goto out;
342fcfc8be1SOlga Kornievskaia }
343fcfc8be1SOlga Kornievskaia
344ec4b0925SOlga Kornievskaia res = ERR_PTR(-ENOMEM);
345ec4b0925SOlga Kornievskaia len = strlen(SSC_READ_NAME_BODY) + 16;
3464fb547beSTrond Myklebust read_name = kzalloc(len, GFP_KERNEL);
347ec4b0925SOlga Kornievskaia if (read_name == NULL)
348ec4b0925SOlga Kornievskaia goto out;
349ec4b0925SOlga Kornievskaia snprintf(read_name, len, SSC_READ_NAME_BODY, read_name_gen++);
350ec4b0925SOlga Kornievskaia
351f6957b71SAl Viro r_ino = nfs_fhget(ss_mnt->mnt_sb, src_fh, fattr);
352ec4b0925SOlga Kornievskaia if (IS_ERR(r_ino)) {
353ec4b0925SOlga Kornievskaia res = ERR_CAST(r_ino);
354f751c545SOlga Kornievskaia goto out_free_name;
355ec4b0925SOlga Kornievskaia }
356ec4b0925SOlga Kornievskaia
357aa97a3efSTrond Myklebust filep = alloc_file_pseudo(r_ino, ss_mnt, read_name, O_RDONLY,
358ec4b0925SOlga Kornievskaia r_ino->i_fop);
359ec4b0925SOlga Kornievskaia if (IS_ERR(filep)) {
360ec4b0925SOlga Kornievskaia res = ERR_CAST(filep);
361fcfc8be1SOlga Kornievskaia iput(r_ino);
362f751c545SOlga Kornievskaia goto out_free_name;
363ec4b0925SOlga Kornievskaia }
364ec4b0925SOlga Kornievskaia
3656f1c1d95SChenXiaoSong ctx = alloc_nfs_open_context(filep->f_path.dentry,
3666f1c1d95SChenXiaoSong flags_to_mode(filep->f_flags), filep);
367ec4b0925SOlga Kornievskaia if (IS_ERR(ctx)) {
368ec4b0925SOlga Kornievskaia res = ERR_CAST(ctx);
369ec4b0925SOlga Kornievskaia goto out_filep;
370ec4b0925SOlga Kornievskaia }
371ec4b0925SOlga Kornievskaia
372ec4b0925SOlga Kornievskaia res = ERR_PTR(-EINVAL);
373ec4b0925SOlga Kornievskaia sp = nfs4_get_state_owner(server, ctx->cred, GFP_KERNEL);
374ec4b0925SOlga Kornievskaia if (sp == NULL)
375ec4b0925SOlga Kornievskaia goto out_ctx;
376ec4b0925SOlga Kornievskaia
377ec4b0925SOlga Kornievskaia ctx->state = nfs4_get_open_state(r_ino, sp);
378ec4b0925SOlga Kornievskaia if (ctx->state == NULL)
379ec4b0925SOlga Kornievskaia goto out_stateowner;
380ec4b0925SOlga Kornievskaia
3810b9018b9SOlga Kornievskaia set_bit(NFS_SRV_SSC_COPY_STATE, &ctx->state->flags);
382ec4b0925SOlga Kornievskaia memcpy(&ctx->state->open_stateid.other, &stateid->other,
383ec4b0925SOlga Kornievskaia NFS4_STATEID_OTHER_SIZE);
384ec4b0925SOlga Kornievskaia update_open_stateid(ctx->state, stateid, NULL, filep->f_mode);
385fe8eb820SDai Ngo set_bit(NFS_OPEN_STATE, &ctx->state->flags);
386ec4b0925SOlga Kornievskaia
387ec4b0925SOlga Kornievskaia nfs_file_set_open_context(filep, ctx);
388ec4b0925SOlga Kornievskaia put_nfs_open_context(ctx);
389ec4b0925SOlga Kornievskaia
390ec4b0925SOlga Kornievskaia file_ra_state_init(&filep->f_ra, filep->f_mapping->host->i_mapping);
391ec4b0925SOlga Kornievskaia res = filep;
392f751c545SOlga Kornievskaia out_free_name:
393f751c545SOlga Kornievskaia kfree(read_name);
394ec4b0925SOlga Kornievskaia out:
395156cd285STrond Myklebust nfs_free_fattr(fattr);
396ec4b0925SOlga Kornievskaia return res;
397ec4b0925SOlga Kornievskaia out_stateowner:
398ec4b0925SOlga Kornievskaia nfs4_put_state_owner(sp);
399ec4b0925SOlga Kornievskaia out_ctx:
400ec4b0925SOlga Kornievskaia put_nfs_open_context(ctx);
401ec4b0925SOlga Kornievskaia out_filep:
402ec4b0925SOlga Kornievskaia fput(filep);
403f751c545SOlga Kornievskaia goto out_free_name;
404ec4b0925SOlga Kornievskaia }
4050cfcd405SDai Ngo
__nfs42_ssc_close(struct file * filep)4060cfcd405SDai Ngo static void __nfs42_ssc_close(struct file *filep)
407ec4b0925SOlga Kornievskaia {
408ec4b0925SOlga Kornievskaia struct nfs_open_context *ctx = nfs_file_open_context(filep);
409ec4b0925SOlga Kornievskaia
410ec4b0925SOlga Kornievskaia ctx->state->flags = 0;
411ec4b0925SOlga Kornievskaia }
4120cfcd405SDai Ngo
4130cfcd405SDai Ngo static const struct nfs4_ssc_client_ops nfs4_ssc_clnt_ops_tbl = {
4140cfcd405SDai Ngo .sco_open = __nfs42_ssc_open,
4150cfcd405SDai Ngo .sco_close = __nfs42_ssc_close,
4160cfcd405SDai Ngo };
4170cfcd405SDai Ngo
4180cfcd405SDai Ngo /**
4190cfcd405SDai Ngo * nfs42_ssc_register_ops - Wrapper to register NFS_V4 ops in nfs_common
4200cfcd405SDai Ngo *
4210cfcd405SDai Ngo * Return values:
4220cfcd405SDai Ngo * None
4230cfcd405SDai Ngo */
nfs42_ssc_register_ops(void)4240cfcd405SDai Ngo void nfs42_ssc_register_ops(void)
4250cfcd405SDai Ngo {
4260cfcd405SDai Ngo nfs42_ssc_register(&nfs4_ssc_clnt_ops_tbl);
4270cfcd405SDai Ngo }
4280cfcd405SDai Ngo
4290cfcd405SDai Ngo /**
4300cfcd405SDai Ngo * nfs42_ssc_unregister_ops - wrapper to un-register NFS_V4 ops in nfs_common
4310cfcd405SDai Ngo *
4320cfcd405SDai Ngo * Return values:
4330cfcd405SDai Ngo * None.
4340cfcd405SDai Ngo */
nfs42_ssc_unregister_ops(void)4350cfcd405SDai Ngo void nfs42_ssc_unregister_ops(void)
4360cfcd405SDai Ngo {
4370cfcd405SDai Ngo nfs42_ssc_unregister(&nfs4_ssc_clnt_ops_tbl);
4380cfcd405SDai Ngo }
4396b7153daSChristoph Hellwig #endif /* CONFIG_NFS_V4_2 */
440bea51b30SPeng Tao
nfs4_setlease(struct file * file,int arg,struct file_lock ** lease,void ** priv)441*ed5f17f6SLuca Vizzarro static int nfs4_setlease(struct file *file, int arg, struct file_lock **lease,
442e93a5e93STrond Myklebust void **priv)
443e93a5e93STrond Myklebust {
444e93a5e93STrond Myklebust return nfs4_proc_setlease(file, arg, lease, priv);
445e93a5e93STrond Myklebust }
446e93a5e93STrond Myklebust
447ce4ef7c0SBryan Schumaker const struct file_operations nfs4_file_operations = {
4483aa2d199SAl Viro .read_iter = nfs_file_read,
449edaf4369SAl Viro .write_iter = nfs_file_write,
450ce4ef7c0SBryan Schumaker .mmap = nfs_file_mmap,
451ce4ef7c0SBryan Schumaker .open = nfs4_file_open,
4525445b1fbSTrond Myklebust .flush = nfs4_file_flush,
453ce4ef7c0SBryan Schumaker .release = nfs_file_release,
4544ff79bc7SChristoph Hellwig .fsync = nfs_file_fsync,
455ce4ef7c0SBryan Schumaker .lock = nfs_lock,
456ce4ef7c0SBryan Schumaker .flock = nfs_flock,
457a7db5034SDavid Howells .splice_read = nfs_file_splice_read,
4584da54c21SAl Viro .splice_write = iter_file_splice_write,
459ce4ef7c0SBryan Schumaker .check_flags = nfs_check_flags,
460e93a5e93STrond Myklebust .setlease = nfs4_setlease,
4616b7153daSChristoph Hellwig #ifdef CONFIG_NFS_V4_2
4622e72448bSAnna Schumaker .copy_file_range = nfs4_copy_file_range,
4636b7153daSChristoph Hellwig .llseek = nfs4_file_llseek,
4646b7153daSChristoph Hellwig .fallocate = nfs42_fallocate,
4652e5dfc99SDarrick J. Wong .remap_file_range = nfs42_remap_file_range,
4666b7153daSChristoph Hellwig #else
4676b7153daSChristoph Hellwig .llseek = nfs_file_llseek,
4686b7153daSChristoph Hellwig #endif
469ce4ef7c0SBryan Schumaker };
470