Blame view

fs/nfs/nfs4file.c 5.87 KB
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
1
2
3
4
5
  /*
   *  linux/fs/nfs/file.c
   *
   *  Copyright (C) 1992  Rick Sladkey
   */
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
6
  #include <linux/fs.h>
bea51b30b   Peng Tao   nfs42: add NFS_IO...
7
  #include <linux/file.h>
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
8
  #include <linux/falloc.h>
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
9
  #include <linux/nfs_fs.h>
0f42a6a9b   Christoph Hellwig   nfs: use btrfs io...
10
  #include <uapi/linux/btrfs.h>	/* BTRFS_IOC_CLONE/BTRFS_IOC_CLONE_RANGE */
5445b1fbd   Trond Myklebust   NFSv4: Respect th...
11
  #include "delegation.h"
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
12
  #include "internal.h"
5445b1fbd   Trond Myklebust   NFSv4: Respect th...
13
  #include "iostat.h"
a4ff14688   David Howells   NFS4: Open files ...
14
  #include "fscache.h"
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
15
  #include "pnfs.h"
81b79afb5   Trond Myklebust   NFSv4: Allow trac...
16
  #include "nfstrace.h"
1c6dcbe5c   Anna Schumaker   NFS: Implement SEEK
17
18
19
  #ifdef CONFIG_NFS_V4_2
  #include "nfs42.h"
  #endif
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
20
21
22
23
24
25
  #define NFSDBG_FACILITY		NFSDBG_FILE
  
  static int
  nfs4_file_open(struct inode *inode, struct file *filp)
  {
  	struct nfs_open_context *ctx;
be62a1a8f   Miklos Szeredi   nfs: use file_den...
26
  	struct dentry *dentry = file_dentry(filp);
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
27
28
29
30
31
  	struct dentry *parent = NULL;
  	struct inode *dir;
  	unsigned openflags = filp->f_flags;
  	struct iattr attr;
  	int err;
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
32
33
34
35
36
37
38
39
  	/*
  	 * If no cached dentry exists or if it's negative, NFSv4 handled the
  	 * opens in ->lookup() or ->create().
  	 *
  	 * We only get this far for a cached positive dentry.  We skipped
  	 * revalidation, so handle it here by dropping the dentry and returning
  	 * -EOPENSTALE.  The VFS will retry the lookup/create/open.
  	 */
6de1472f1   Al Viro   nfs: use %p[dD] i...
40
41
  	dprintk("NFS: open file(%pd2)
  ", dentry);
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
42

18a600897   Benjamin Coddington   nfs: verify open ...
43
44
45
  	err = nfs_check_flags(openflags);
  	if (err)
  		return err;
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
46
47
48
49
50
51
52
  	if ((openflags & O_ACCMODE) == 3)
  		openflags--;
  
  	/* We can't create new files here */
  	openflags &= ~(O_CREAT|O_EXCL);
  
  	parent = dget_parent(dentry);
2b0143b5c   David Howells   VFS: normal files...
53
  	dir = d_inode(parent);
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
54

be62a1a8f   Miklos Szeredi   nfs: use file_den...
55
  	ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode);
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
56
57
58
59
60
61
62
63
  	err = PTR_ERR(ctx);
  	if (IS_ERR(ctx))
  		goto out;
  
  	attr.ia_valid = ATTR_OPEN;
  	if (openflags & O_TRUNC) {
  		attr.ia_valid |= ATTR_SIZE;
  		attr.ia_size = 0;
9e1681c2e   Trond Myklebust   NFSv4: Truncating...
64
  		nfs_sync_inode(inode);
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
65
  	}
c5c3fb5f9   Kinglong Mee   NFS: Make opened ...
66
  	inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, NULL);
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
67
68
69
70
71
72
73
74
75
76
77
78
79
  	if (IS_ERR(inode)) {
  		err = PTR_ERR(inode);
  		switch (err) {
  		case -EPERM:
  		case -EACCES:
  		case -EDQUOT:
  		case -ENOSPC:
  		case -EROFS:
  			goto out_put_ctx;
  		default:
  			goto out_drop;
  		}
  	}
2b0143b5c   David Howells   VFS: normal files...
80
  	if (inode != d_inode(dentry))
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
81
82
83
84
  		goto out_drop;
  
  	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
  	nfs_file_set_open_context(filp, ctx);
f1fe29b4a   David Howells   NFS: Use i_writec...
85
  	nfs_fscache_open_file(inode, filp);
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
86
87
88
89
90
91
92
93
94
95
96
97
98
  	err = 0;
  
  out_put_ctx:
  	put_nfs_open_context(ctx);
  out:
  	dput(parent);
  	return err;
  
  out_drop:
  	d_drop(dentry);
  	err = -EOPENSTALE;
  	goto out_put_ctx;
  }
5445b1fbd   Trond Myklebust   NFSv4: Respect th...
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  /*
   * Flush all dirty pages, and check for write errors.
   */
  static int
  nfs4_file_flush(struct file *file, fl_owner_t id)
  {
  	struct inode	*inode = file_inode(file);
  
  	dprintk("NFS: flush(%pD2)
  ", file);
  
  	nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
  	if ((file->f_mode & FMODE_WRITE) == 0)
  		return 0;
  
  	/*
  	 * If we're holding a write delegation, then check if we're required
  	 * to flush the i/o on close. If not, then just start the i/o now.
  	 */
  	if (!nfs4_delegation_flush_on_close(inode))
  		return filemap_fdatawrite(file->f_mapping);
  
  	/* Flush writes to the server and return any errors */
  	return vfs_fsync(file, 0);
  }
1c6dcbe5c   Anna Schumaker   NFS: Implement SEEK
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  #ifdef CONFIG_NFS_V4_2
  static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
  {
  	loff_t ret;
  
  	switch (whence) {
  	case SEEK_HOLE:
  	case SEEK_DATA:
  		ret = nfs42_proc_llseek(filep, offset, whence);
  		if (ret != -ENOTSUPP)
  			return ret;
  	default:
  		return nfs_file_llseek(filep, offset, whence);
  	}
  }
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
139
140
141
142
143
144
145
146
  
  static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t len)
  {
  	struct inode *inode = file_inode(filep);
  	long ret;
  
  	if (!S_ISREG(inode->i_mode))
  		return -EOPNOTSUPP;
624bd5b7b   Anna Schumaker   nfs: Add DEALLOCA...
147
  	if ((mode != 0) && (mode != (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)))
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
148
149
150
151
152
  		return -EOPNOTSUPP;
  
  	ret = inode_newsize_ok(inode, offset + len);
  	if (ret < 0)
  		return ret;
624bd5b7b   Anna Schumaker   nfs: Add DEALLOCA...
153
  	if (mode & FALLOC_FL_PUNCH_HOLE)
f830f7ddd   Anna Schumaker   NFS: Reduce time ...
154
155
  		return nfs42_proc_deallocate(filep, offset, len);
  	return nfs42_proc_allocate(filep, offset, len);
f4ac1674f   Anna Schumaker   nfs: Add ALLOCATE...
156
  }
bea51b30b   Peng Tao   nfs42: add NFS_IO...
157

04b38d601   Christoph Hellwig   vfs: pull btrfs c...
158
159
  static int nfs42_clone_file_range(struct file *src_file, loff_t src_off,
  		struct file *dst_file, loff_t dst_off, u64 count)
bea51b30b   Peng Tao   nfs42: add NFS_IO...
160
161
  {
  	struct inode *dst_inode = file_inode(dst_file);
811b7b85d   Peng Tao   nfs42: respect cl...
162
  	struct nfs_server *server = NFS_SERVER(dst_inode);
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
163
  	struct inode *src_inode = file_inode(src_file);
811b7b85d   Peng Tao   nfs42: respect cl...
164
  	unsigned int bs = server->clone_blksize;
21fad313d   Christoph Hellwig   nfs: allow intra-...
165
  	bool same_inode = false;
bea51b30b   Peng Tao   nfs42: add NFS_IO...
166
  	int ret;
811b7b85d   Peng Tao   nfs42: respect cl...
167
168
169
170
  	/* check alignment w.r.t. clone_blksize */
  	ret = -EINVAL;
  	if (bs) {
  		if (!IS_ALIGNED(src_off, bs) || !IS_ALIGNED(dst_off, bs))
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
171
  			goto out;
811b7b85d   Peng Tao   nfs42: respect cl...
172
  		if (!IS_ALIGNED(count, bs) && i_size_read(src_inode) != (src_off + count))
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
173
  			goto out;
811b7b85d   Peng Tao   nfs42: respect cl...
174
  	}
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
175
176
  	if (src_inode == dst_inode)
  		same_inode = true;
21fad313d   Christoph Hellwig   nfs: allow intra-...
177

bea51b30b   Peng Tao   nfs42: add NFS_IO...
178
  	/* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */
21fad313d   Christoph Hellwig   nfs: allow intra-...
179
  	if (same_inode) {
5955102c9   Al Viro   wrappers for ->i_...
180
  		inode_lock(src_inode);
21fad313d   Christoph Hellwig   nfs: allow intra-...
181
  	} else if (dst_inode < src_inode) {
5955102c9   Al Viro   wrappers for ->i_...
182
183
  		inode_lock_nested(dst_inode, I_MUTEX_PARENT);
  		inode_lock_nested(src_inode, I_MUTEX_CHILD);
bea51b30b   Peng Tao   nfs42: add NFS_IO...
184
  	} else {
5955102c9   Al Viro   wrappers for ->i_...
185
186
  		inode_lock_nested(src_inode, I_MUTEX_PARENT);
  		inode_lock_nested(dst_inode, I_MUTEX_CHILD);
bea51b30b   Peng Tao   nfs42: add NFS_IO...
187
188
189
190
191
192
193
194
195
196
  	}
  
  	/* flush all pending writes on both src and dst so that server
  	 * has the latest data */
  	ret = nfs_sync_inode(src_inode);
  	if (ret)
  		goto out_unlock;
  	ret = nfs_sync_inode(dst_inode);
  	if (ret)
  		goto out_unlock;
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
197
  	ret = nfs42_proc_clone(src_file, dst_file, src_off, dst_off, count);
bea51b30b   Peng Tao   nfs42: add NFS_IO...
198
199
200
201
202
203
204
  
  	/* truncate inode page cache of the dst range so that future reads can fetch
  	 * new data from server */
  	if (!ret)
  		truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1);
  
  out_unlock:
21fad313d   Christoph Hellwig   nfs: allow intra-...
205
  	if (same_inode) {
5955102c9   Al Viro   wrappers for ->i_...
206
  		inode_unlock(src_inode);
21fad313d   Christoph Hellwig   nfs: allow intra-...
207
  	} else if (dst_inode < src_inode) {
5955102c9   Al Viro   wrappers for ->i_...
208
209
  		inode_unlock(src_inode);
  		inode_unlock(dst_inode);
bea51b30b   Peng Tao   nfs42: add NFS_IO...
210
  	} else {
5955102c9   Al Viro   wrappers for ->i_...
211
212
  		inode_unlock(dst_inode);
  		inode_unlock(src_inode);
bea51b30b   Peng Tao   nfs42: add NFS_IO...
213
  	}
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
214
  out:
bea51b30b   Peng Tao   nfs42: add NFS_IO...
215
216
  	return ret;
  }
6b7153da2   Christoph Hellwig   nfs: reduce the a...
217
  #endif /* CONFIG_NFS_V4_2 */
bea51b30b   Peng Tao   nfs42: add NFS_IO...
218

ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
219
  const struct file_operations nfs4_file_operations = {
3aa2d199f   Al Viro   nfs: switch to ->...
220
  	.read_iter	= nfs_file_read,
edaf43694   Al Viro   nfs: switch to ->...
221
  	.write_iter	= nfs_file_write,
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
222
223
  	.mmap		= nfs_file_mmap,
  	.open		= nfs4_file_open,
5445b1fbd   Trond Myklebust   NFSv4: Respect th...
224
  	.flush		= nfs4_file_flush,
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
225
  	.release	= nfs_file_release,
4ff79bc70   Christoph Hellwig   nfs: remove nfs4_...
226
  	.fsync		= nfs_file_fsync,
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
227
228
229
  	.lock		= nfs_lock,
  	.flock		= nfs_flock,
  	.splice_read	= nfs_file_splice_read,
4da54c218   Al Viro   nfs: switch to it...
230
  	.splice_write	= iter_file_splice_write,
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
231
  	.check_flags	= nfs_check_flags,
1c994a090   Jeff Layton   locks: consolidat...
232
  	.setlease	= simple_nosetlease,
6b7153da2   Christoph Hellwig   nfs: reduce the a...
233
234
235
  #ifdef CONFIG_NFS_V4_2
  	.llseek		= nfs4_file_llseek,
  	.fallocate	= nfs42_fallocate,
04b38d601   Christoph Hellwig   vfs: pull btrfs c...
236
  	.clone_file_range = nfs42_clone_file_range,
6b7153da2   Christoph Hellwig   nfs: reduce the a...
237
238
239
  #else
  	.llseek		= nfs_file_llseek,
  #endif
ce4ef7c0a   Bryan Schumaker   NFS: Split out NF...
240
  };