Blame view

fs/nfs/file.c 23.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   *  linux/fs/nfs/file.c
   *
   *  Copyright (C) 1992  Rick Sladkey
   *
   *  Changes Copyright (C) 1994 by Florian La Roche
   *   - Do not copy data too often around in the kernel.
   *   - In nfs_file_read the return value of kmalloc wasn't checked.
   *   - Put in a better version of read look-ahead buffering. Original idea
   *     and implementation by Wai S Kok elekokws@ee.nus.sg.
   *
   *  Expire cache on write to a file by Wai S Kok (Oct 1994).
   *
   *  Total rewrite of read side for new NFS buffer cache.. Linus.
   *
   *  nfs regular file handling functions
   */
  
  #include <linux/time.h>
  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/fcntl.h>
  #include <linux/stat.h>
  #include <linux/nfs_fs.h>
  #include <linux/nfs_mount.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  #include <linux/pagemap.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
28
  #include <linux/aio.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
29
  #include <linux/gfp.h>
b608b283a   Trond Myklebust   NFS: kswapd must ...
30
  #include <linux/swap.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
  
  #include <asm/uaccess.h>
  #include <asm/system.h>
  
  #include "delegation.h"
94387fb1a   Trond Myklebust   NFS: Add the help...
36
  #include "internal.h"
91d5b4702   Chuck Lever   NFS: add I/O perf...
37
  #include "iostat.h"
545db45f0   David Howells   NFS: FS-Cache pag...
38
  #include "fscache.h"
e5e940170   Benny Halevy   NFS: create and d...
39
  #include "pnfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
  
  #define NFSDBG_FACILITY		NFSDBG_FILE
f0f37e2f7   Alexey Dobriyan   const: mark struc...
42
  static const struct vm_operations_struct nfs_file_vm_ops;
94387fb1a   Trond Myklebust   NFS: Add the help...
43

92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
44
  const struct inode_operations nfs_file_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
  	.permission	= nfs_permission,
  	.getattr	= nfs_getattr,
  	.setattr	= nfs_setattr,
  };
b7fa0554c   Andreas Gruenbacher   [PATCH] NFS: Add ...
49
  #ifdef CONFIG_NFS_V3
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
50
  const struct inode_operations nfs3_file_inode_operations = {
b7fa0554c   Andreas Gruenbacher   [PATCH] NFS: Add ...
51
52
53
54
55
56
57
58
59
  	.permission	= nfs_permission,
  	.getattr	= nfs_getattr,
  	.setattr	= nfs_setattr,
  	.listxattr	= nfs3_listxattr,
  	.getxattr	= nfs3_getxattr,
  	.setxattr	= nfs3_setxattr,
  	.removexattr	= nfs3_removexattr,
  };
  #endif  /* CONFIG_NFS_v3 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  /* Hack for future NFS swap support */
  #ifndef IS_SWAPFILE
  # define IS_SWAPFILE(inode)	(0)
  #endif
  
  static int nfs_check_flags(int flags)
  {
  	if ((flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT))
  		return -EINVAL;
  
  	return 0;
  }
  
  /*
   * Open file
   */
  static int
  nfs_file_open(struct inode *inode, struct file *filp)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  	int res;
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
80
81
  	dprintk("NFS: open file(%s/%s)
  ",
cc0dd2d10   Chuck Lever   NFS: Make nfs_ope...
82
83
  			filp->f_path.dentry->d_parent->d_name.name,
  			filp->f_path.dentry->d_name.name);
c2459dc46   Chuck Lever   NFS: Proper accou...
84
  	nfs_inc_stats(inode, NFSIOS_VFSOPEN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
  	res = nfs_check_flags(filp->f_flags);
  	if (res)
  		return res;
46cb650c2   Trond Myklebust   NFS: Remove the r...
88
  	res = nfs_open(inode, filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
91
92
93
94
  	return res;
  }
  
  static int
  nfs_file_release(struct inode *inode, struct file *filp)
  {
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
95
96
  	dprintk("NFS: release(%s/%s)
  ",
6f276e49f   Rakib Mullick   nfs: Fix unused v...
97
98
  			filp->f_path.dentry->d_parent->d_name.name,
  			filp->f_path.dentry->d_name.name);
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
99

91d5b4702   Chuck Lever   NFS: add I/O perf...
100
  	nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
46cb650c2   Trond Myklebust   NFS: Remove the r...
101
  	return nfs_release(inode, filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  }
980802e31   Trond Myklebust   [PATCH] NFS: Ensu...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  /**
   * nfs_revalidate_size - Revalidate the file size
   * @inode - pointer to inode struct
   * @file - pointer to struct file
   *
   * Revalidates the file length. This is basically a wrapper around
   * nfs_revalidate_inode() that takes into account the fact that we may
   * have cached writes (in which case we don't care about the server's
   * idea of what the file length is), or O_DIRECT (in which case we
   * shouldn't trust the cache).
   */
  static int nfs_revalidate_file_size(struct inode *inode, struct file *filp)
  {
  	struct nfs_server *server = NFS_SERVER(inode);
  	struct nfs_inode *nfsi = NFS_I(inode);
d7cf8dd01   Trond Myklebust   NFSv4: Allow attr...
118
119
  	if (nfs_have_delegated_attributes(inode))
  		goto out_noreval;
980802e31   Trond Myklebust   [PATCH] NFS: Ensu...
120
121
  	if (filp->f_flags & O_DIRECT)
  		goto force_reval;
d7cf8dd01   Trond Myklebust   NFSv4: Allow attr...
122
123
124
125
126
127
  	if (nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
  		goto force_reval;
  	if (nfs_attribute_timeout(inode))
  		goto force_reval;
  out_noreval:
  	return 0;
980802e31   Trond Myklebust   [PATCH] NFS: Ensu...
128
129
130
131
132
133
  force_reval:
  	return __nfs_revalidate_inode(server, inode);
  }
  
  static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
  {
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
134
135
  	dprintk("NFS: llseek file(%s/%s, %lld, %d)
  ",
b84e06c58   Chuck Lever   NFS: Make nfs_lls...
136
137
138
  			filp->f_path.dentry->d_parent->d_name.name,
  			filp->f_path.dentry->d_name.name,
  			offset, origin);
06222e491   Josef Bacik   fs: handle SEEK_H...
139
140
141
142
  	/*
  	 * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate
  	 * the cached file length
  	 */
6c5296174   Trond Myklebust   NFS: Fix a regres...
143
  	if (origin != SEEK_SET && origin != SEEK_CUR) {
980802e31   Trond Myklebust   [PATCH] NFS: Ensu...
144
  		struct inode *inode = filp->f_mapping->host;
d5e66348b   Trond Myklebust   NFS: Fix nfs_file...
145

980802e31   Trond Myklebust   [PATCH] NFS: Ensu...
146
147
148
  		int retval = nfs_revalidate_file_size(inode, filp);
  		if (retval < 0)
  			return (loff_t)retval;
79835a710   Andi Kleen   nfs: drop unneces...
149
  	}
d5e66348b   Trond Myklebust   NFS: Fix nfs_file...
150

79835a710   Andi Kleen   nfs: drop unneces...
151
  	return generic_file_llseek(filp, offset, origin);
980802e31   Trond Myklebust   [PATCH] NFS: Ensu...
152
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
  /*
   * Flush all dirty pages, and check for write errors.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
   */
  static int
75e1fcc0b   Miklos Szeredi   [PATCH] vfs: add ...
157
  nfs_file_flush(struct file *file, fl_owner_t id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  {
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
159
160
  	struct dentry	*dentry = file->f_path.dentry;
  	struct inode	*inode = dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161

6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
162
163
164
165
  	dprintk("NFS: flush(%s/%s)
  ",
  			dentry->d_parent->d_name.name,
  			dentry->d_name.name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166

c2459dc46   Chuck Lever   NFS: Proper accou...
167
  	nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
  	if ((file->f_mode & FMODE_WRITE) == 0)
  		return 0;
7b159fc18   Trond Myklebust   NFS: Fall back to...
170

7fe5c398f   Trond Myklebust   NFS: Optimise NFS...
171
  	/* Flush writes to the server and return any errors */
af7fa1650   Trond Myklebust   NFS: Fix up the f...
172
  	return vfs_fsync(file, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
  }
  
  static ssize_t
027445c37   Badari Pulavarty   [PATCH] Vectorize...
176
177
  nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
  		unsigned long nr_segs, loff_t pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  {
01cce933d   Josef "Jeff" Sipek   [PATCH] nfs: chan...
179
  	struct dentry * dentry = iocb->ki_filp->f_path.dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
  	struct inode * inode = dentry->d_inode;
  	ssize_t result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  	if (iocb->ki_filp->f_flags & O_DIRECT)
027445c37   Badari Pulavarty   [PATCH] Vectorize...
183
  		return nfs_file_direct_read(iocb, iov, nr_segs, pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184

6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
185
186
  	dprintk("NFS: read(%s/%s, %lu@%lu)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  		dentry->d_parent->d_name.name, dentry->d_name.name,
6f276e49f   Rakib Mullick   nfs: Fix unused v...
188
  		(unsigned long) iov_length(iov, nr_segs), (unsigned long) pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189

44b11874f   Trond Myklebust   NFS: Separate met...
190
  	result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
4184dcf2d   Chuck Lever   NFS: Fix byte acc...
191
  	if (!result) {
027445c37   Badari Pulavarty   [PATCH] Vectorize...
192
  		result = generic_file_aio_read(iocb, iov, nr_segs, pos);
4184dcf2d   Chuck Lever   NFS: Fix byte acc...
193
194
195
  		if (result > 0)
  			nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
  	return result;
  }
  
  static ssize_t
f0930fffa   Jens Axboe   sendfile: convert...
200
201
202
  nfs_file_splice_read(struct file *filp, loff_t *ppos,
  		     struct pipe_inode_info *pipe, size_t count,
  		     unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  {
01cce933d   Josef "Jeff" Sipek   [PATCH] nfs: chan...
204
  	struct dentry *dentry = filp->f_path.dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
  	struct inode *inode = dentry->d_inode;
  	ssize_t res;
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
207
208
  	dprintk("NFS: splice_read(%s/%s, %lu@%Lu)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
  		dentry->d_parent->d_name.name, dentry->d_name.name,
  		(unsigned long) count, (unsigned long long) *ppos);
44b11874f   Trond Myklebust   NFS: Separate met...
211
  	res = nfs_revalidate_mapping(inode, filp->f_mapping);
aa2f1ef10   Chuck Lever   NFS: Account for ...
212
  	if (!res) {
f0930fffa   Jens Axboe   sendfile: convert...
213
  		res = generic_file_splice_read(filp, ppos, pipe, count, flags);
aa2f1ef10   Chuck Lever   NFS: Account for ...
214
215
216
  		if (res > 0)
  			nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, res);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
220
221
222
  	return res;
  }
  
  static int
  nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
  {
01cce933d   Josef "Jeff" Sipek   [PATCH] nfs: chan...
223
  	struct dentry *dentry = file->f_path.dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
  	struct inode *inode = dentry->d_inode;
  	int	status;
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
226
227
  	dprintk("NFS: mmap(%s/%s)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
  		dentry->d_parent->d_name.name, dentry->d_name.name);
e1ebfd33b   Trond Myklebust   NFS: Kill the "de...
229
230
231
232
  	/* Note: generic_file_mmap() returns ENOSYS on nommu systems
  	 *       so we call that before revalidating the mapping
  	 */
  	status = generic_file_mmap(file, vma);
94387fb1a   Trond Myklebust   NFS: Add the help...
233
234
  	if (!status) {
  		vma->vm_ops = &nfs_file_vm_ops;
e1ebfd33b   Trond Myklebust   NFS: Kill the "de...
235
  		status = nfs_revalidate_mapping(inode, file->f_mapping);
94387fb1a   Trond Myklebust   NFS: Add the help...
236
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
241
242
243
  	return status;
  }
  
  /*
   * Flush any dirty pages for this process, and check for write errors.
   * The return status from this call provides a reliable indication of
   * whether any write errors occurred for this process.
af7fa1650   Trond Myklebust   NFS: Fix up the f...
244
245
246
247
248
   *
   * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to
   * disk, but it retrieves and clears ctx->error after synching, despite
   * the two being set at the same time in nfs_context_set_write_error().
   * This is because the former is used to notify the _next_ call to
25985edce   Lucas De Marchi   Fix common misspe...
249
   * nfs_file_write() that a write error occurred, and hence cause it to
af7fa1650   Trond Myklebust   NFS: Fix up the f...
250
   * fall back to doing a synchronous write.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
   */
  static int
02c24a821   Josef Bacik   fs: push i_mutex ...
253
  nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  {
7ea808591   Christoph Hellwig   drop unused dentr...
255
  	struct dentry *dentry = file->f_path.dentry;
cd3758e37   Trond Myklebust   NFS: Replace file...
256
  	struct nfs_open_context *ctx = nfs_file_open_context(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  	struct inode *inode = dentry->d_inode;
af7fa1650   Trond Myklebust   NFS: Fix up the f...
258
259
  	int have_error, status;
  	int ret = 0;
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
260
261
  	dprintk("NFS: fsync file(%s/%s) datasync %d
  ",
549177863   Chuck Lever   NFS: Make nfs_fsy...
262
263
  			dentry->d_parent->d_name.name, dentry->d_name.name,
  			datasync);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264

02c24a821   Josef Bacik   fs: push i_mutex ...
265
  	ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
02c24a821   Josef Bacik   fs: push i_mutex ...
266
  	mutex_lock(&inode->i_mutex);
91d5b4702   Chuck Lever   NFS: add I/O perf...
267
  	nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
af7fa1650   Trond Myklebust   NFS: Fix up the f...
268
269
  	have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
  	status = nfs_commit_inode(inode, FLUSH_SYNC);
2edb6bc38   NeilBrown   NFS - fix recent ...
270
271
  	if (status >= 0 && ret < 0)
  		status = ret;
af7fa1650   Trond Myklebust   NFS: Fix up the f...
272
273
274
  	have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
  	if (have_error)
  		ret = xchg(&ctx->error, 0);
0702099bd   J. R. Okajima   NFS: fix the retu...
275
  	if (!ret && status < 0)
af7fa1650   Trond Myklebust   NFS: Fix up the f...
276
  		ret = status;
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
277
278
  	if (!ret && !datasync)
  		/* application has asked for meta-data sync */
ef3115378   Andy Adamson   NFSv4.1 convert l...
279
  		ret = pnfs_layoutcommit_inode(inode, true);
02c24a821   Josef Bacik   fs: push i_mutex ...
280
  	mutex_unlock(&inode->i_mutex);
af7fa1650   Trond Myklebust   NFS: Fix up the f...
281
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
  }
  
  /*
38c73044f   Peter Staubach   NFS: read-modify-...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
   * Decide whether a read/modify/write cycle may be more efficient
   * then a modify/write/read cycle when writing to a page in the
   * page cache.
   *
   * The modify/write/read cycle may occur if a page is read before
   * being completely filled by the writer.  In this situation, the
   * page must be completely written to stable storage on the server
   * before it can be refilled by reading in the page from the server.
   * This can lead to expensive, small, FILE_SYNC mode writes being
   * done.
   *
   * It may be more efficient to read the page first if the file is
   * open for reading in addition to writing, the page is not marked
   * as Uptodate, it is not dirty or waiting to be committed,
   * indicating that it was previously allocated and then modified,
   * that there were valid bytes of data in that range of the file,
   * and that the new data won't completely replace the old data in
   * that range of the file.
   */
  static int nfs_want_read_modify_write(struct file *file, struct page *page,
  			loff_t pos, unsigned len)
  {
  	unsigned int pglen = nfs_page_length(page);
  	unsigned int offset = pos & (PAGE_CACHE_SIZE - 1);
  	unsigned int end = offset + len;
  
  	if ((file->f_mode & FMODE_READ) &&	/* open for read? */
  	    !PageUptodate(page) &&		/* Uptodate? */
  	    !PagePrivate(page) &&		/* i/o request already? */
  	    pglen &&				/* valid bytes of file? */
  	    (end < pglen || offset))		/* replace all valid bytes? */
  		return 1;
  	return 0;
  }
  
  /*
4899f9c85   Nick Piggin   nfs: convert to n...
321
322
323
   * This does the "real" work of the write. We must allocate and lock the
   * page to be sent back to the generic routine, which then copies the
   * data from user space.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
327
   *
   * If the writer ends up delaying the write, the writer needs to
   * increment the page use counts until he is done with the page.
   */
4899f9c85   Nick Piggin   nfs: convert to n...
328
329
330
  static int nfs_write_begin(struct file *file, struct address_space *mapping,
  			loff_t pos, unsigned len, unsigned flags,
  			struct page **pagep, void **fsdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  {
4899f9c85   Nick Piggin   nfs: convert to n...
332
  	int ret;
38c73044f   Peter Staubach   NFS: read-modify-...
333
  	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
4899f9c85   Nick Piggin   nfs: convert to n...
334
  	struct page *page;
38c73044f   Peter Staubach   NFS: read-modify-...
335
  	int once_thru = 0;
4899f9c85   Nick Piggin   nfs: convert to n...
336

b7eaefaa8   Chuck Lever   NFS: Add debuggin...
337
338
339
340
341
  	dfprintk(PAGECACHE, "NFS: write_begin(%s/%s(%ld), %u@%lld)
  ",
  		file->f_path.dentry->d_parent->d_name.name,
  		file->f_path.dentry->d_name.name,
  		mapping->host->i_ino, len, (long long) pos);
38c73044f   Peter Staubach   NFS: read-modify-...
342
  start:
72cb77f4a   Trond Myklebust   NFS: Throttle pag...
343
344
345
346
347
348
349
350
  	/*
  	 * Prevent starvation issues if someone is doing a consistency
  	 * sync-to-disk
  	 */
  	ret = wait_on_bit(&NFS_I(mapping->host)->flags, NFS_INO_FLUSHING,
  			nfs_wait_bit_killable, TASK_KILLABLE);
  	if (ret)
  		return ret;
54566b2c1   Nick Piggin   fs: symlink write...
351
  	page = grab_cache_page_write_begin(mapping, index, flags);
4899f9c85   Nick Piggin   nfs: convert to n...
352
353
354
355
356
357
358
359
  	if (!page)
  		return -ENOMEM;
  	*pagep = page;
  
  	ret = nfs_flush_incompatible(file, page);
  	if (ret) {
  		unlock_page(page);
  		page_cache_release(page);
38c73044f   Peter Staubach   NFS: read-modify-...
360
361
362
363
364
365
366
  	} else if (!once_thru &&
  		   nfs_want_read_modify_write(file, page, pos, len)) {
  		once_thru = 1;
  		ret = nfs_readpage(file, page);
  		page_cache_release(page);
  		if (!ret)
  			goto start;
4899f9c85   Nick Piggin   nfs: convert to n...
367
368
  	}
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  }
4899f9c85   Nick Piggin   nfs: convert to n...
370
371
372
  static int nfs_write_end(struct file *file, struct address_space *mapping,
  			loff_t pos, unsigned len, unsigned copied,
  			struct page *page, void *fsdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  {
4899f9c85   Nick Piggin   nfs: convert to n...
374
375
  	unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
  	int status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376

b7eaefaa8   Chuck Lever   NFS: Add debuggin...
377
378
379
380
381
  	dfprintk(PAGECACHE, "NFS: write_end(%s/%s(%ld), %u@%lld)
  ",
  		file->f_path.dentry->d_parent->d_name.name,
  		file->f_path.dentry->d_name.name,
  		mapping->host->i_ino, len, (long long) pos);
efc91ed01   Trond Myklebust   NFS: Optimise app...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
  	/*
  	 * Zero any uninitialised parts of the page, and then mark the page
  	 * as up to date if it turns out that we're extending the file.
  	 */
  	if (!PageUptodate(page)) {
  		unsigned pglen = nfs_page_length(page);
  		unsigned end = offset + len;
  
  		if (pglen == 0) {
  			zero_user_segments(page, 0, offset,
  					end, PAGE_CACHE_SIZE);
  			SetPageUptodate(page);
  		} else if (end >= pglen) {
  			zero_user_segment(page, end, PAGE_CACHE_SIZE);
  			if (offset == 0)
  				SetPageUptodate(page);
  		} else
  			zero_user_segment(page, pglen, PAGE_CACHE_SIZE);
  	}
4899f9c85   Nick Piggin   nfs: convert to n...
401
  	status = nfs_updatepage(file, page, offset, copied);
4899f9c85   Nick Piggin   nfs: convert to n...
402
403
404
  
  	unlock_page(page);
  	page_cache_release(page);
3d509e545   Chuck Lever   NFS: nfs_write_en...
405
406
407
  	if (status < 0)
  		return status;
  	return copied;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  }
6b9b3514a   David Howells   NFS: Add comment ...
409
410
411
412
  /*
   * Partially or wholly invalidate a page
   * - Release the private state associated with a page if undergoing complete
   *   page invalidation
545db45f0   David Howells   NFS: FS-Cache pag...
413
   * - Called if either PG_private or PG_fscache is set on the page
6b9b3514a   David Howells   NFS: Add comment ...
414
415
   * - Caller holds page lock
   */
2ff28e22b   NeilBrown   [PATCH] Make addr...
416
  static void nfs_invalidate_page(struct page *page, unsigned long offset)
cd52ed355   Trond Myklebust   NFS: Avoid races ...
417
  {
b7eaefaa8   Chuck Lever   NFS: Add debuggin...
418
419
  	dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %lu)
  ", page, offset);
1c75950b9   Trond Myklebust   NFS: cleanup of n...
420
421
  	if (offset != 0)
  		return;
d2ccddf04   Trond Myklebust   NFS: Flesh out nf...
422
  	/* Cancel any unstarted writes on this page */
1b3b4a1a2   Trond Myklebust   NFS: Fix a write ...
423
  	nfs_wb_page_cancel(page->mapping->host, page);
545db45f0   David Howells   NFS: FS-Cache pag...
424
425
  
  	nfs_fscache_invalidate_page(page, page->mapping->host);
cd52ed355   Trond Myklebust   NFS: Avoid races ...
426
  }
6b9b3514a   David Howells   NFS: Add comment ...
427
428
  /*
   * Attempt to release the private state associated with a page
545db45f0   David Howells   NFS: FS-Cache pag...
429
   * - Called if either PG_private or PG_fscache is set on the page
6b9b3514a   David Howells   NFS: Add comment ...
430
431
432
   * - Caller holds page lock
   * - Return true (may release page) or false (may not)
   */
cd52ed355   Trond Myklebust   NFS: Avoid races ...
433
434
  static int nfs_release_page(struct page *page, gfp_t gfp)
  {
b608b283a   Trond Myklebust   NFS: kswapd must ...
435
  	struct address_space *mapping = page->mapping;
b7eaefaa8   Chuck Lever   NFS: Add debuggin...
436
437
  	dfprintk(PAGECACHE, "NFS: release_page(%p)
  ", page);
d812e5758   Trond Myklebust   NFS: Prevent anot...
438
  	/* Only do I/O if gfp is a superset of GFP_KERNEL */
b608b283a   Trond Myklebust   NFS: kswapd must ...
439
440
441
442
443
444
445
446
  	if (mapping && (gfp & GFP_KERNEL) == GFP_KERNEL) {
  		int how = FLUSH_SYNC;
  
  		/* Don't let kswapd deadlock waiting for OOM RPC calls */
  		if (current_is_kswapd())
  			how = 0;
  		nfs_commit_inode(mapping->host, how);
  	}
e3db7691e   Trond Myklebust   [PATCH] NFS: Fix ...
447
  	/* If PagePrivate() is set, then the page is not freeable */
545db45f0   David Howells   NFS: FS-Cache pag...
448
449
450
  	if (PagePrivate(page))
  		return 0;
  	return nfs_fscache_release_page(page, gfp);
e3db7691e   Trond Myklebust   [PATCH] NFS: Fix ...
451
  }
6b9b3514a   David Howells   NFS: Add comment ...
452
453
454
455
  /*
   * Attempt to clear the private state associated with a page when an error
   * occurs that requires the cached contents of an inode to be written back or
   * destroyed
545db45f0   David Howells   NFS: FS-Cache pag...
456
   * - Called if either PG_private or fscache is set on the page
6b9b3514a   David Howells   NFS: Add comment ...
457
458
459
   * - Caller holds page lock
   * - Return 0 if successful, -error otherwise
   */
e3db7691e   Trond Myklebust   [PATCH] NFS: Fix ...
460
461
  static int nfs_launder_page(struct page *page)
  {
b7eaefaa8   Chuck Lever   NFS: Add debuggin...
462
  	struct inode *inode = page->mapping->host;
545db45f0   David Howells   NFS: FS-Cache pag...
463
  	struct nfs_inode *nfsi = NFS_I(inode);
b7eaefaa8   Chuck Lever   NFS: Add debuggin...
464
465
466
467
  
  	dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)
  ",
  		inode->i_ino, (long long)page_offset(page));
545db45f0   David Howells   NFS: FS-Cache pag...
468
  	nfs_fscache_wait_on_page_write(nfsi, page);
b7eaefaa8   Chuck Lever   NFS: Add debuggin...
469
  	return nfs_wb_page(inode, page);
cd52ed355   Trond Myklebust   NFS: Avoid races ...
470
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
471
  const struct address_space_operations nfs_file_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
  	.readpage = nfs_readpage,
  	.readpages = nfs_readpages,
9cccef950   Trond Myklebust   NFS: Clean up wri...
474
  	.set_page_dirty = __set_page_dirty_nobuffers,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
  	.writepage = nfs_writepage,
  	.writepages = nfs_writepages,
4899f9c85   Nick Piggin   nfs: convert to n...
477
478
  	.write_begin = nfs_write_begin,
  	.write_end = nfs_write_end,
cd52ed355   Trond Myklebust   NFS: Avoid races ...
479
480
  	.invalidatepage = nfs_invalidate_page,
  	.releasepage = nfs_release_page,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  	.direct_IO = nfs_direct_IO,
074cc1dee   Trond Myklebust   NFS: Add a ->migr...
482
  	.migratepage = nfs_migrate_page,
e3db7691e   Trond Myklebust   [PATCH] NFS: Fix ...
483
  	.launder_page = nfs_launder_page,
f590f333f   Andi Kleen   HWPOISON: Enable ...
484
  	.error_remove_page = generic_error_remove_page,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
  };
6b9b3514a   David Howells   NFS: Add comment ...
486
487
488
489
490
  /*
   * Notification that a PTE pointing to an NFS page is about to be made
   * writable, implying that someone is about to modify the page through a
   * shared-writable mapping
   */
c2ec175c3   Nick Piggin   mm: page_mkwrite ...
491
  static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
94387fb1a   Trond Myklebust   NFS: Add the help...
492
  {
c2ec175c3   Nick Piggin   mm: page_mkwrite ...
493
  	struct page *page = vmf->page;
94387fb1a   Trond Myklebust   NFS: Add the help...
494
  	struct file *filp = vma->vm_file;
b7eaefaa8   Chuck Lever   NFS: Add debuggin...
495
  	struct dentry *dentry = filp->f_path.dentry;
94387fb1a   Trond Myklebust   NFS: Add the help...
496
  	unsigned pagelen;
bc4866b6e   Trond Myklebust   NFS: Don't SIGBUS...
497
  	int ret = VM_FAULT_NOPAGE;
4899f9c85   Nick Piggin   nfs: convert to n...
498
  	struct address_space *mapping;
94387fb1a   Trond Myklebust   NFS: Add the help...
499

b7eaefaa8   Chuck Lever   NFS: Add debuggin...
500
501
502
503
504
  	dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%s/%s(%ld), offset %lld)
  ",
  		dentry->d_parent->d_name.name, dentry->d_name.name,
  		filp->f_mapping->host->i_ino,
  		(long long)page_offset(page));
545db45f0   David Howells   NFS: FS-Cache pag...
505
506
  	/* make sure the cache has finished storing the page */
  	nfs_fscache_wait_on_page_write(NFS_I(dentry->d_inode), page);
94387fb1a   Trond Myklebust   NFS: Add the help...
507
  	lock_page(page);
4899f9c85   Nick Piggin   nfs: convert to n...
508
  	mapping = page->mapping;
b7eaefaa8   Chuck Lever   NFS: Add debuggin...
509
  	if (mapping != dentry->d_inode->i_mapping)
8b1f9ee56   Trond Myklebust   NFS: Optimise nfs...
510
  		goto out_unlock;
94387fb1a   Trond Myklebust   NFS: Add the help...
511
  	pagelen = nfs_page_length(page);
8b1f9ee56   Trond Myklebust   NFS: Optimise nfs...
512
513
  	if (pagelen == 0)
  		goto out_unlock;
4899f9c85   Nick Piggin   nfs: convert to n...
514

bc4866b6e   Trond Myklebust   NFS: Don't SIGBUS...
515
516
517
518
  	ret = VM_FAULT_LOCKED;
  	if (nfs_flush_incompatible(filp, page) == 0 &&
  	    nfs_updatepage(filp, page, 0, pagelen) == 0)
  		goto out;
8b1f9ee56   Trond Myklebust   NFS: Optimise nfs...
519

bc4866b6e   Trond Myklebust   NFS: Don't SIGBUS...
520
  	ret = VM_FAULT_SIGBUS;
8b1f9ee56   Trond Myklebust   NFS: Optimise nfs...
521
522
  out_unlock:
  	unlock_page(page);
bc4866b6e   Trond Myklebust   NFS: Don't SIGBUS...
523
524
  out:
  	return ret;
94387fb1a   Trond Myklebust   NFS: Add the help...
525
  }
f0f37e2f7   Alexey Dobriyan   const: mark struc...
526
  static const struct vm_operations_struct nfs_file_vm_ops = {
94387fb1a   Trond Myklebust   NFS: Add the help...
527
528
529
  	.fault = filemap_fault,
  	.page_mkwrite = nfs_vm_page_mkwrite,
  };
7b159fc18   Trond Myklebust   NFS: Fall back to...
530
531
532
  static int nfs_need_sync_write(struct file *filp, struct inode *inode)
  {
  	struct nfs_open_context *ctx;
6b2f3d1f7   Christoph Hellwig   vfs: Implement pr...
533
  	if (IS_SYNC(inode) || (filp->f_flags & O_DSYNC))
7b159fc18   Trond Myklebust   NFS: Fall back to...
534
  		return 1;
cd3758e37   Trond Myklebust   NFS: Replace file...
535
  	ctx = nfs_file_open_context(filp);
7b159fc18   Trond Myklebust   NFS: Fall back to...
536
537
538
539
  	if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags))
  		return 1;
  	return 0;
  }
027445c37   Badari Pulavarty   [PATCH] Vectorize...
540
541
  static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
  				unsigned long nr_segs, loff_t pos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  {
01cce933d   Josef "Jeff" Sipek   [PATCH] nfs: chan...
543
  	struct dentry * dentry = iocb->ki_filp->f_path.dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
  	struct inode * inode = dentry->d_inode;
7e381172c   Chuck Lever   NFS: Improve NFS ...
545
  	unsigned long written = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
  	ssize_t result;
027445c37   Badari Pulavarty   [PATCH] Vectorize...
547
  	size_t count = iov_length(iov, nr_segs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  	if (iocb->ki_filp->f_flags & O_DIRECT)
027445c37   Badari Pulavarty   [PATCH] Vectorize...
550
  		return nfs_file_direct_write(iocb, iov, nr_segs, pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551

6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
552
553
  	dprintk("NFS: write(%s/%s, %lu@%Ld)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  		dentry->d_parent->d_name.name, dentry->d_name.name,
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
555
  		(unsigned long) count, (long long) pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
558
559
  
  	result = -EBUSY;
  	if (IS_SWAPFILE(inode))
  		goto out_swapfile;
7d52e8627   Trond Myklebust   [PATCH] NFS: Clea...
560
561
562
563
564
565
566
  	/*
  	 * O_APPEND implies that we must revalidate the file length.
  	 */
  	if (iocb->ki_filp->f_flags & O_APPEND) {
  		result = nfs_revalidate_file_size(inode, iocb->ki_filp);
  		if (result)
  			goto out;
fe51beecc   Trond Myklebust   [PATCH] NFS: Ensu...
567
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
570
571
  
  	result = count;
  	if (!count)
  		goto out;
027445c37   Badari Pulavarty   [PATCH] Vectorize...
572
  	result = generic_file_aio_write(iocb, iov, nr_segs, pos);
7e381172c   Chuck Lever   NFS: Improve NFS ...
573
574
  	if (result > 0)
  		written = result;
6b2f3d1f7   Christoph Hellwig   vfs: Implement pr...
575
  	/* Return error values for O_DSYNC and IS_SYNC() */
7b159fc18   Trond Myklebust   NFS: Fall back to...
576
  	if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) {
af7fa1650   Trond Myklebust   NFS: Fix up the f...
577
  		int err = vfs_fsync(iocb->ki_filp, 0);
200baa211   Trond Myklebust   NFS: Remove nfs_w...
578
579
580
  		if (err < 0)
  			result = err;
  	}
7e381172c   Chuck Lever   NFS: Improve NFS ...
581
582
  	if (result > 0)
  		nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
584
585
586
587
588
589
590
  out:
  	return result;
  
  out_swapfile:
  	printk(KERN_INFO "NFS: attempt to write to active swap file!
  ");
  	goto out;
  }
bf40d3435   Suresh Jayaraman   NFS: add support ...
591
592
593
594
595
596
  static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe,
  				     struct file *filp, loff_t *ppos,
  				     size_t count, unsigned int flags)
  {
  	struct dentry *dentry = filp->f_path.dentry;
  	struct inode *inode = dentry->d_inode;
7e381172c   Chuck Lever   NFS: Improve NFS ...
597
  	unsigned long written = 0;
bf40d3435   Suresh Jayaraman   NFS: add support ...
598
599
600
601
602
603
604
605
606
607
  	ssize_t ret;
  
  	dprintk("NFS splice_write(%s/%s, %lu@%llu)
  ",
  		dentry->d_parent->d_name.name, dentry->d_name.name,
  		(unsigned long) count, (unsigned long long) *ppos);
  
  	/*
  	 * The combination of splice and an O_APPEND destination is disallowed.
  	 */
bf40d3435   Suresh Jayaraman   NFS: add support ...
608
  	ret = generic_file_splice_write(pipe, filp, ppos, count, flags);
7e381172c   Chuck Lever   NFS: Improve NFS ...
609
610
  	if (ret > 0)
  		written = ret;
bf40d3435   Suresh Jayaraman   NFS: add support ...
611
  	if (ret >= 0 && nfs_need_sync_write(filp, inode)) {
af7fa1650   Trond Myklebust   NFS: Fix up the f...
612
  		int err = vfs_fsync(filp, 0);
bf40d3435   Suresh Jayaraman   NFS: add support ...
613
614
615
  		if (err < 0)
  			ret = err;
  	}
7e381172c   Chuck Lever   NFS: Improve NFS ...
616
617
  	if (ret > 0)
  		nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written);
bf40d3435   Suresh Jayaraman   NFS: add support ...
618
619
  	return ret;
  }
5eebde232   Suresh Jayaraman   nfs: introduce mo...
620
621
  static int
  do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
623
624
  {
  	struct inode *inode = filp->f_mapping->host;
  	int status = 0;
21ac19d48   Sergey Vlasov   NFS: Fix fcntl F_...
625
  	unsigned int saved_type = fl->fl_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626

039c4d7a8   Trond Myklebust   NFS: Fix up a rac...
627
  	/* Try local locking first */
6d34ac199   J. Bruce Fields   locks: make posix...
628
629
630
  	posix_test_lock(filp, fl);
  	if (fl->fl_type != F_UNLCK) {
  		/* found a conflict */
039c4d7a8   Trond Myklebust   NFS: Fix up a rac...
631
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
  	}
21ac19d48   Sergey Vlasov   NFS: Fix fcntl F_...
633
  	fl->fl_type = saved_type;
039c4d7a8   Trond Myklebust   NFS: Fix up a rac...
634
635
636
  
  	if (nfs_have_delegation(inode, FMODE_READ))
  		goto out_noconflict;
5eebde232   Suresh Jayaraman   nfs: introduce mo...
637
  	if (is_local)
039c4d7a8   Trond Myklebust   NFS: Fix up a rac...
638
639
640
641
  		goto out_noconflict;
  
  	status = NFS_PROTO(inode)->lock(filp, cmd, fl);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
  	return status;
039c4d7a8   Trond Myklebust   NFS: Fix up a rac...
643
644
645
  out_noconflict:
  	fl->fl_type = F_UNLCK;
  	goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
  }
  
  static int do_vfs_lock(struct file *file, struct file_lock *fl)
  {
  	int res = 0;
  	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
  		case FL_POSIX:
  			res = posix_lock_file_wait(file, fl);
  			break;
  		case FL_FLOCK:
  			res = flock_lock_file_wait(file, fl);
  			break;
  		default:
  			BUG();
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
  	return res;
  }
5eebde232   Suresh Jayaraman   nfs: introduce mo...
663
664
  static int
  do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
  {
  	struct inode *inode = filp->f_mapping->host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
  	int status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
671
  	/*
  	 * Flush all pending writes before doing anything
  	 * with locks..
  	 */
29884df0d   Trond Myklebust   NFS: Fix another ...
672
  	nfs_sync_mapping(filp->f_mapping);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
675
676
677
  
  	/* NOTE: special case
  	 * 	If we're signalled while cleaning up locks on process exit, we
  	 * 	still need to complete the unlock.
  	 */
5eebde232   Suresh Jayaraman   nfs: introduce mo...
678
679
680
681
682
  	/*
  	 * Use local locking if mounted with "-onolock" or with appropriate
  	 * "-olocal_lock="
  	 */
  	if (!is_local)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
  		status = NFS_PROTO(inode)->lock(filp, cmd, fl);
  	else
  		status = do_vfs_lock(filp, fl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686
687
  	return status;
  }
5eebde232   Suresh Jayaraman   nfs: introduce mo...
688
  static int
6b96724e5   Ricardo Labiaga   Revalidate caches...
689
690
691
692
693
  is_time_granular(struct timespec *ts) {
  	return ((ts->tv_sec == 0) && (ts->tv_nsec <= 1000));
  }
  
  static int
5eebde232   Suresh Jayaraman   nfs: introduce mo...
694
  do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
696
  {
  	struct inode *inode = filp->f_mapping->host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  	int status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
  	/*
  	 * Flush all pending writes before doing anything
  	 * with locks..
  	 */
29884df0d   Trond Myklebust   NFS: Fix another ...
702
703
  	status = nfs_sync_mapping(filp->f_mapping);
  	if (status != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
  		goto out;
5eebde232   Suresh Jayaraman   nfs: introduce mo...
705
706
707
708
709
  	/*
  	 * Use local locking if mounted with "-onolock" or with appropriate
  	 * "-olocal_lock="
  	 */
  	if (!is_local)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
710
  		status = NFS_PROTO(inode)->lock(filp, cmd, fl);
c4d7c402b   Trond Myklebust   NFS: Remove the b...
711
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
  		status = do_vfs_lock(filp, fl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
  	if (status < 0)
  		goto out;
6b96724e5   Ricardo Labiaga   Revalidate caches...
715

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
  	/*
6b96724e5   Ricardo Labiaga   Revalidate caches...
717
718
719
720
  	 * Revalidate the cache if the server has time stamps granular
  	 * enough to detect subsecond changes.  Otherwise, clear the
  	 * cache to prevent missing any changes.
  	 *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
  	 * This makes locking act as a cache coherency point.
  	 */
29884df0d   Trond Myklebust   NFS: Fix another ...
723
  	nfs_sync_mapping(filp->f_mapping);
6b96724e5   Ricardo Labiaga   Revalidate caches...
724
725
726
727
728
729
  	if (!nfs_have_delegation(inode, FMODE_READ)) {
  		if (is_time_granular(&NFS_SERVER(inode)->time_delta))
  			__nfs_revalidate_inode(NFS_SERVER(inode), inode);
  		else
  			nfs_zap_caches(inode);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
735
736
737
738
  	return status;
  }
  
  /*
   * Lock a (portion of) a file
   */
  static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
  {
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
739
  	struct inode *inode = filp->f_mapping->host;
2116271a3   Trond Myklebust   NFS: Add correct ...
740
  	int ret = -ENOLCK;
5eebde232   Suresh Jayaraman   nfs: introduce mo...
741
  	int is_local = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742

6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
743
744
745
746
  	dprintk("NFS: lock(%s/%s, t=%x, fl=%x, r=%lld:%lld)
  ",
  			filp->f_path.dentry->d_parent->d_name.name,
  			filp->f_path.dentry->d_name.name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
  			fl->fl_type, fl->fl_flags,
  			(long long)fl->fl_start, (long long)fl->fl_end);
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
749

91d5b4702   Chuck Lever   NFS: add I/O perf...
750
  	nfs_inc_stats(inode, NFSIOS_VFSLOCK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
  
  	/* No mandatory locks over NFS */
dfad9441b   Pavel Emelyanov   NFS: clean up exp...
753
  	if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
2116271a3   Trond Myklebust   NFS: Add correct ...
754
  		goto out_err;
5eebde232   Suresh Jayaraman   nfs: introduce mo...
755
756
  	if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FCNTL)
  		is_local = 1;
2116271a3   Trond Myklebust   NFS: Add correct ...
757
758
759
760
761
  	if (NFS_PROTO(inode)->lock_check_bounds != NULL) {
  		ret = NFS_PROTO(inode)->lock_check_bounds(fl);
  		if (ret < 0)
  			goto out_err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
763
  
  	if (IS_GETLK(cmd))
5eebde232   Suresh Jayaraman   nfs: introduce mo...
764
  		ret = do_getlk(filp, cmd, fl, is_local);
2116271a3   Trond Myklebust   NFS: Add correct ...
765
  	else if (fl->fl_type == F_UNLCK)
5eebde232   Suresh Jayaraman   nfs: introduce mo...
766
  		ret = do_unlk(filp, cmd, fl, is_local);
2116271a3   Trond Myklebust   NFS: Add correct ...
767
  	else
5eebde232   Suresh Jayaraman   nfs: introduce mo...
768
  		ret = do_setlk(filp, cmd, fl, is_local);
2116271a3   Trond Myklebust   NFS: Add correct ...
769
770
  out_err:
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
773
774
775
776
777
  }
  
  /*
   * Lock a (portion of) a file
   */
  static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
  {
5eebde232   Suresh Jayaraman   nfs: introduce mo...
778
779
  	struct inode *inode = filp->f_mapping->host;
  	int is_local = 0;
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
780
781
782
783
  	dprintk("NFS: flock(%s/%s, t=%x, fl=%x)
  ",
  			filp->f_path.dentry->d_parent->d_name.name,
  			filp->f_path.dentry->d_name.name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
  			fl->fl_type, fl->fl_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
  	if (!(fl->fl_flags & FL_FLOCK))
  		return -ENOLCK;
5eebde232   Suresh Jayaraman   nfs: introduce mo...
787
788
  	if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FLOCK)
  		is_local = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
790
791
792
793
794
  	/* We're simulating flock() locks using posix locks on the server */
  	fl->fl_owner = (fl_owner_t)filp;
  	fl->fl_start = 0;
  	fl->fl_end = OFFSET_MAX;
  
  	if (fl->fl_type == F_UNLCK)
5eebde232   Suresh Jayaraman   nfs: introduce mo...
795
796
  		return do_unlk(filp, cmd, fl, is_local);
  	return do_setlk(filp, cmd, fl, is_local);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
  }
370f6599e   J. Bruce Fields   nfs: disable leas...
798

6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
799
800
801
802
  /*
   * There is no protocol support for leases, so we have no way to implement
   * them correctly in the face of opens by other clients.
   */
370f6599e   J. Bruce Fields   nfs: disable leas...
803
804
  static int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
  {
6da24bc9c   Chuck Lever   NFS: Use NFSDBG_F...
805
806
807
808
  	dprintk("NFS: setlease(%s/%s, arg=%ld)
  ",
  			file->f_path.dentry->d_parent->d_name.name,
  			file->f_path.dentry->d_name.name, arg);
370f6599e   J. Bruce Fields   nfs: disable leas...
809
810
  	return -EINVAL;
  }
1788ea6e3   Jeff Layton   nfs: when attempt...
811

0486958f5   Jeff Layton   nfs: move nfs_fil...
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
  const struct file_operations nfs_file_operations = {
  	.llseek		= nfs_file_llseek,
  	.read		= do_sync_read,
  	.write		= do_sync_write,
  	.aio_read	= nfs_file_read,
  	.aio_write	= nfs_file_write,
  	.mmap		= nfs_file_mmap,
  	.open		= nfs_file_open,
  	.flush		= nfs_file_flush,
  	.release	= nfs_file_release,
  	.fsync		= nfs_file_fsync,
  	.lock		= nfs_lock,
  	.flock		= nfs_flock,
  	.splice_read	= nfs_file_splice_read,
  	.splice_write	= nfs_file_splice_write,
  	.check_flags	= nfs_check_flags,
  	.setlease	= nfs_setlease,
  };
1788ea6e3   Jeff Layton   nfs: when attempt...
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
  #ifdef CONFIG_NFS_V4
  static int
  nfs4_file_open(struct inode *inode, struct file *filp)
  {
  	/*
  	 * NFSv4 opens are handled in d_lookup and d_revalidate. If we get to
  	 * this point, then something is very wrong
  	 */
  	dprintk("NFS: %s called! inode=%p filp=%p
  ", __func__, inode, filp);
  	return -ENOTDIR;
  }
  
  const struct file_operations nfs4_file_operations = {
  	.llseek		= nfs_file_llseek,
  	.read		= do_sync_read,
  	.write		= do_sync_write,
  	.aio_read	= nfs_file_read,
  	.aio_write	= nfs_file_write,
  	.mmap		= nfs_file_mmap,
  	.open		= nfs4_file_open,
  	.flush		= nfs_file_flush,
  	.release	= nfs_file_release,
  	.fsync		= nfs_file_fsync,
  	.lock		= nfs_lock,
  	.flock		= nfs_flock,
  	.splice_read	= nfs_file_splice_read,
  	.splice_write	= nfs_file_splice_write,
  	.check_flags	= nfs_check_flags,
  	.setlease	= nfs_setlease,
  };
  #endif /* CONFIG_NFS_V4 */