Blame view

fs/nfs/inode.c 46.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   *  linux/fs/nfs/inode.c
   *
   *  Copyright (C) 1992  Rick Sladkey
   *
   *  nfs inode and superblock handling functions
   *
526719ba5   Alan Cox   Switch to a valid...
8
   *  Modularised by Alan Cox <alan@lxorguk.ukuu.org.uk>, while hacking some
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
14
   *  experimental NFS changes. Modularisation taken straight from SYS5 fs.
   *
   *  Change to nfs_read_super() to permit NFS mounts to multi-homed hosts.
   *  J.S.Peatfield@damtp.cam.ac.uk
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <linux/module.h>
  #include <linux/init.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
17
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
23
24
25
26
  #include <linux/time.h>
  #include <linux/kernel.h>
  #include <linux/mm.h>
  #include <linux/string.h>
  #include <linux/stat.h>
  #include <linux/errno.h>
  #include <linux/unistd.h>
  #include <linux/sunrpc/clnt.h>
  #include <linux/sunrpc/stats.h>
4ece3a2d1   Chuck Lever   NFS: add RPC I/O ...
27
  #include <linux/sunrpc/metrics.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
  #include <linux/nfs_fs.h>
  #include <linux/nfs_mount.h>
  #include <linux/nfs4_mount.h>
  #include <linux/lockd/bind.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
  #include <linux/seq_file.h>
  #include <linux/mount.h>
  #include <linux/nfs_idmap.h>
  #include <linux/vfs.h>
9cdb3883c   Manoj Naik   NFSv4: Ensure cli...
36
37
  #include <linux/inet.h>
  #include <linux/nfs_xdr.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
38
  #include <linux/slab.h>
3fa0b4e20   Frank Filz   (try3-resend) Fix...
39
  #include <linux/compat.h>
d310310cb   Jeff Layton   Freezer / sunrpc ...
40
  #include <linux/freezer.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
  
  #include <asm/system.h>
  #include <asm/uaccess.h>
4ce79717c   Trond Myklebust   [PATCH] NFS: Head...
44
  #include "nfs4_fs.h"
a72b44222   Trond Myklebust   NFSv4: Allow user...
45
  #include "callback.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  #include "delegation.h"
d9ef5a8c2   Chuck Lever   NFS: introduce me...
47
  #include "iostat.h"
f7b422b17   David Howells   NFS: Split fs/nfs...
48
  #include "internal.h"
8ec442ae4   David Howells   NFS: Register NFS...
49
  #include "fscache.h"
e571cbf1a   Trond Myklebust   NFS: Add a dns re...
50
  #include "dns_resolve.h"
e5e940170   Benny Halevy   NFS: create and d...
51
  #include "pnfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
  
  #define NFSDBG_FACILITY		NFSDBG_VFS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

f43bf0beb   Trond Myklebust   NFS: Add a boot p...
55
56
57
  #define NFS_64_BIT_INODE_NUMBERS_ENABLED	1
  
  /* Default is to see 64-bit inode numbers */
90ab5ee94   Rusty Russell   module_param: mak...
58
  static bool enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED;
f43bf0beb   Trond Myklebust   NFS: Add a boot p...
59

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  static void nfs_invalidate_inode(struct inode *);
24aa1fe67   Trond Myklebust   NFS: Fix a few fu...
61
  static int nfs_update_inode(struct inode *, struct nfs_fattr *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

e18b890bb   Christoph Lameter   [PATCH] slab: rem...
63
  static struct kmem_cache * nfs_inode_cachep;
b7fa0554c   Andreas Gruenbacher   [PATCH] NFS: Add ...
64

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
69
  static inline unsigned long
  nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
  {
  	return nfs_fileid_to_ino_t(fattr->fileid);
  }
f43bf0beb   Trond Myklebust   NFS: Add a boot p...
70
  /**
72cb77f4a   Trond Myklebust   NFS: Throttle pag...
71
72
73
74
75
76
77
   * nfs_wait_bit_killable - helper for functions that are sleeping on bit locks
   * @word: long word containing the bit lock
   */
  int nfs_wait_bit_killable(void *word)
  {
  	if (fatal_signal_pending(current))
  		return -ERESTARTSYS;
d310310cb   Jeff Layton   Freezer / sunrpc ...
78
  	freezable_schedule();
72cb77f4a   Trond Myklebust   NFS: Throttle pag...
79
80
81
82
  	return 0;
  }
  
  /**
f43bf0beb   Trond Myklebust   NFS: Add a boot p...
83
84
85
86
87
88
89
90
   * nfs_compat_user_ino64 - returns the user-visible inode number
   * @fileid: 64-bit fileid
   *
   * This function returns a 32-bit inode number if the boot parameter
   * nfs.enable_ino64 is zero.
   */
  u64 nfs_compat_user_ino64(u64 fileid)
  {
3fa0b4e20   Frank Filz   (try3-resend) Fix...
91
92
93
94
95
  #ifdef CONFIG_COMPAT
  	compat_ulong_t ino;
  #else	
  	unsigned long ino;
  #endif
f43bf0beb   Trond Myklebust   NFS: Add a boot p...
96
97
98
99
100
101
102
103
  
  	if (enable_ino64)
  		return fileid;
  	ino = fileid;
  	if (sizeof(ino) < sizeof(fileid))
  		ino ^= fileid >> (sizeof(fileid)-sizeof(ino)) * 8;
  	return ino;
  }
b57922d97   Al Viro   convert remaining...
104
  static void nfs_clear_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  {
da6d503aa   Trond Myklebust   NFS: Remove nfs_d...
106
107
108
109
  	/*
  	 * The following should never happen...
  	 */
  	BUG_ON(nfs_have_writebacks(inode));
1c3c07e9f   Trond Myklebust   NFS: Add a new AC...
110
  	BUG_ON(!list_empty(&NFS_I(inode)->open_files));
ada70d942   Trond Myklebust   [PATCH] NFS: Add ...
111
  	nfs_zap_acl_cache(inode);
1c3c07e9f   Trond Myklebust   NFS: Add a new AC...
112
  	nfs_access_zap_cache(inode);
ef79c097b   David Howells   NFS: Use local di...
113
  	nfs_fscache_release_inode_cookie(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  }
b57922d97   Al Viro   convert remaining...
115
116
117
118
119
120
  void nfs_evict_inode(struct inode *inode)
  {
  	truncate_inode_pages(&inode->i_data, 0);
  	end_writeback(inode);
  	nfs_clear_inode(inode);
  }
29884df0d   Trond Myklebust   NFS: Fix another ...
121
122
123
124
125
  /**
   * nfs_sync_mapping - helper to flush all mmapped dirty data to disk
   */
  int nfs_sync_mapping(struct address_space *mapping)
  {
5cf95214c   Trond Myklebust   NFS: Clean up nfs...
126
  	int ret = 0;
29884df0d   Trond Myklebust   NFS: Fix another ...
127

5cf95214c   Trond Myklebust   NFS: Clean up nfs...
128
129
130
131
  	if (mapping->nrpages != 0) {
  		unmap_mapping_range(mapping, 0, 0, 0);
  		ret = nfs_wb_all(mapping->host);
  	}
29884df0d   Trond Myklebust   NFS: Fix another ...
132
133
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
  /*
   * Invalidate the local caches
   */
b37b03b70   Trond Myklebust   NFS: Fix a spinlo...
137
  static void nfs_zap_caches_locked(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
  	int mode = inode->i_mode;
91d5b4702   Chuck Lever   NFS: add I/O perf...
141
  	nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
c7c209730   Trond Myklebust   NFS: Get rid of s...
142
143
  	nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
  	nfsi->attrtimeo_timestamp = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
  
  	memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
  	if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
552968098   Chuck Lever   [PATCH] NFS: spli...
147
  		nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  	else
552968098   Chuck Lever   [PATCH] NFS: spli...
149
  		nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
b37b03b70   Trond Myklebust   NFS: Fix a spinlo...
150
  }
dc59250c6   Chuck Lever   [PATCH] NFS: Intr...
151

b37b03b70   Trond Myklebust   NFS: Fix a spinlo...
152
153
154
155
  void nfs_zap_caches(struct inode *inode)
  {
  	spin_lock(&inode->i_lock);
  	nfs_zap_caches_locked(inode);
dc59250c6   Chuck Lever   [PATCH] NFS: Intr...
156
  	spin_unlock(&inode->i_lock);
ada70d942   Trond Myklebust   [PATCH] NFS: Add ...
157
  }
cd9ae2b6a   Trond Myklebust   [PATCH] NFS: Deal...
158
159
160
161
162
163
164
165
  void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
  {
  	if (mapping->nrpages != 0) {
  		spin_lock(&inode->i_lock);
  		NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
  		spin_unlock(&inode->i_lock);
  	}
  }
f41f74183   Trond Myklebust   NFS: Ensure we za...
166
  void nfs_zap_acl_cache(struct inode *inode)
ada70d942   Trond Myklebust   [PATCH] NFS: Add ...
167
168
169
170
171
172
  {
  	void (*clear_acl_cache)(struct inode *);
  
  	clear_acl_cache = NFS_PROTO(inode)->clear_acl_cache;
  	if (clear_acl_cache != NULL)
  		clear_acl_cache(inode);
dc59250c6   Chuck Lever   [PATCH] NFS: Intr...
173
  	spin_lock(&inode->i_lock);
552968098   Chuck Lever   [PATCH] NFS: spli...
174
  	NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_ACL;
dc59250c6   Chuck Lever   [PATCH] NFS: Intr...
175
  	spin_unlock(&inode->i_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
  }
c48129983   Trond Myklebust   NFS: Fix atime re...
177
178
179
180
181
182
  void nfs_invalidate_atime(struct inode *inode)
  {
  	spin_lock(&inode->i_lock);
  	NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
  	spin_unlock(&inode->i_lock);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  /*
b37b03b70   Trond Myklebust   NFS: Fix a spinlo...
184
185
   * Invalidate, but do not unhash, the inode.
   * NB: must be called with inode->i_lock held!
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
   */
b37b03b70   Trond Myklebust   NFS: Fix a spinlo...
187
  static void nfs_invalidate_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  {
3a10c30ac   Benny Halevy   nfs: obliterate N...
189
  	set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
b37b03b70   Trond Myklebust   NFS: Fix a spinlo...
190
  	nfs_zap_caches_locked(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  }
  
  struct nfs_find_desc {
  	struct nfs_fh		*fh;
  	struct nfs_fattr	*fattr;
  };
  
  /*
   * In NFSv3 we can have 64bit inode numbers. In order to support
   * this, and re-exported directories (also seen in NFSv2)
   * we are forced to allow 2 different inodes to have the same
   * i_ino.
   */
  static int
  nfs_find_actor(struct inode *inode, void *opaque)
  {
  	struct nfs_find_desc	*desc = (struct nfs_find_desc *)opaque;
  	struct nfs_fh		*fh = desc->fh;
  	struct nfs_fattr	*fattr = desc->fattr;
  
  	if (NFS_FILEID(inode) != fattr->fileid)
  		return 0;
  	if (nfs_compare_fh(NFS_FH(inode), fh))
  		return 0;
  	if (is_bad_inode(inode) || NFS_STALE(inode))
  		return 0;
  	return 1;
  }
  
  static int
  nfs_init_locked(struct inode *inode, void *opaque)
  {
  	struct nfs_find_desc	*desc = (struct nfs_find_desc *)opaque;
  	struct nfs_fattr	*fattr = desc->fattr;
99fadcd76   Benny Halevy   nfs: convert NFS_...
225
  	set_nfs_fileid(inode, fattr->fileid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
  	nfs_copy_fh(NFS_FH(inode), desc->fh);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
235
236
237
238
239
  /*
   * This is our front-end to iget that looks up inodes by file handle
   * instead of inode number.
   */
  struct inode *
  nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
  {
  	struct nfs_find_desc desc = {
  		.fh	= fh,
  		.fattr	= fattr
  	};
03f28e3a2   Trond Myklebust   NFS: Make nfs_fhg...
240
  	struct inode *inode = ERR_PTR(-ENOENT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
  	unsigned long hash;
7ebb93159   Bryan Schumaker   NFS: use secinfo ...
242
  	nfs_attr_check_mountpoint(sb, fattr);
533eb4611   Andy Adamson   NFSv4.1: allow nf...
243
244
  	if (((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0) &&
  	    !nfs_attr_use_mounted_on_fileid(fattr))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  		goto out_no_inode;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
246
  	if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  		goto out_no_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
  
  	hash = nfs_fattr_to_ino_t(fattr);
03f28e3a2   Trond Myklebust   NFS: Make nfs_fhg...
250
251
252
  	inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc);
  	if (inode == NULL) {
  		inode = ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  		goto out_no_inode;
03f28e3a2   Trond Myklebust   NFS: Make nfs_fhg...
254
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
  
  	if (inode->i_state & I_NEW) {
  		struct nfs_inode *nfsi = NFS_I(inode);
b0c4fddca   Trond Myklebust   NFS: Cleanup - av...
258
  		unsigned long now = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
261
262
263
264
265
266
  
  		/* We set i_ino for the few things that still rely on it,
  		 * such as stat(2) */
  		inode->i_ino = hash;
  
  		/* We can't support update_atime(), since the server will reset it */
  		inode->i_flags |= S_NOATIME|S_NOCMTIME;
  		inode->i_mode = fattr->mode;
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
267
268
269
270
271
  		if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0
  				&& nfs_server_capable(inode, NFS_CAP_MODE))
  			nfsi->cache_validity |= NFS_INO_INVALID_ATTR
  				| NFS_INO_INVALID_ACCESS
  				| NFS_INO_INVALID_ACL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
  		/* Why so? Because we want revalidate for devices/FIFOs, and
  		 * that's precisely what we have in nfs_file_inode_operations.
  		 */
8fa5c000d   David Howells   NFS: Move rpc_ops...
275
  		inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  		if (S_ISREG(inode->i_mode)) {
1788ea6e3   Jeff Layton   nfs: when attempt...
277
  			inode->i_fop = NFS_SB(sb)->nfs_client->rpc_ops->file_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
  			inode->i_data.a_ops = &nfs_file_aops;
  			inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info;
  		} else if (S_ISDIR(inode->i_mode)) {
8fa5c000d   David Howells   NFS: Move rpc_ops...
281
  			inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
  			inode->i_fop = &nfs_dir_operations;
11de3b11e   Trond Myklebust   NFS: Fix a memory...
283
  			inode->i_data.a_ops = &nfs_dir_aops;
0715dc632   Bryan Schumaker   NFS: remove readd...
284
  			if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS))
3a10c30ac   Benny Halevy   nfs: obliterate N...
285
  				set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
55a975937   Trond Myklebust   NFS: Ensure the c...
286
  			/* Deal with crossing mountpoints */
7ebb93159   Bryan Schumaker   NFS: use secinfo ...
287
288
  			if (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT ||
  					fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
6b97fd3da   Manoj Naik   NFSv4: Follow a r...
289
290
291
292
  				if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
  					inode->i_op = &nfs_referral_inode_operations;
  				else
  					inode->i_op = &nfs_mountpoint_inode_operations;
55a975937   Trond Myklebust   NFS: Ensure the c...
293
  				inode->i_fop = NULL;
36d43a437   David Howells   NFS: Use d_automo...
294
  				inode->i_flags |= S_AUTOMOUNT;
55a975937   Trond Myklebust   NFS: Ensure the c...
295
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
  		} else if (S_ISLNK(inode->i_mode))
  			inode->i_op = &nfs_symlink_inode_operations;
  		else
  			init_special_inode(inode, inode->i_mode, fattr->rdev);
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
300
301
302
  		memset(&inode->i_atime, 0, sizeof(inode->i_atime));
  		memset(&inode->i_mtime, 0, sizeof(inode->i_mtime));
  		memset(&inode->i_ctime, 0, sizeof(inode->i_ctime));
a9a4a87a5   Trond Myklebust   NFS: Use the inod...
303
  		inode->i_version = 0;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
304
  		inode->i_size = 0;
6d6b77f16   Miklos Szeredi   filesystems: add ...
305
  		clear_nlink(inode);
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
306
307
308
309
  		inode->i_uid = -2;
  		inode->i_gid = -2;
  		inode->i_blocks = 0;
  		memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
33801147a   Trond Myklebust   NFS: Optimise ino...
310
  		nfsi->read_cache_jiffies = fattr->time_start;
4704f0e27   Trond Myklebust   NFS: Fix the reso...
311
  		nfsi->attr_gencount = fattr->gencount;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
312
313
  		if (fattr->valid & NFS_ATTR_FATTR_ATIME)
  			inode->i_atime = fattr->atime;
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
314
315
  		else if (nfs_server_capable(inode, NFS_CAP_ATIME))
  			nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
316
317
  		if (fattr->valid & NFS_ATTR_FATTR_MTIME)
  			inode->i_mtime = fattr->mtime;
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
318
319
320
  		else if (nfs_server_capable(inode, NFS_CAP_MTIME))
  			nfsi->cache_validity |= NFS_INO_INVALID_ATTR
  				| NFS_INO_INVALID_DATA;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
321
322
  		if (fattr->valid & NFS_ATTR_FATTR_CTIME)
  			inode->i_ctime = fattr->ctime;
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
323
324
325
326
  		else if (nfs_server_capable(inode, NFS_CAP_CTIME))
  			nfsi->cache_validity |= NFS_INO_INVALID_ATTR
  				| NFS_INO_INVALID_ACCESS
  				| NFS_INO_INVALID_ACL;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
327
  		if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
a9a4a87a5   Trond Myklebust   NFS: Use the inod...
328
  			inode->i_version = fattr->change_attr;
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
329
330
331
  		else if (nfs_server_capable(inode, NFS_CAP_CHANGE_ATTR))
  			nfsi->cache_validity |= NFS_INO_INVALID_ATTR
  				| NFS_INO_INVALID_DATA;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
332
333
  		if (fattr->valid & NFS_ATTR_FATTR_SIZE)
  			inode->i_size = nfs_size_to_loff_t(fattr->size);
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
334
335
336
337
  		else
  			nfsi->cache_validity |= NFS_INO_INVALID_ATTR
  				| NFS_INO_INVALID_DATA
  				| NFS_INO_REVAL_PAGECACHE;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
338
  		if (fattr->valid & NFS_ATTR_FATTR_NLINK)
bfe868486   Miklos Szeredi   filesystems: add ...
339
  			set_nlink(inode, fattr->nlink);
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
340
341
  		else if (nfs_server_capable(inode, NFS_CAP_NLINK))
  			nfsi->cache_validity |= NFS_INO_INVALID_ATTR;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
342
343
  		if (fattr->valid & NFS_ATTR_FATTR_OWNER)
  			inode->i_uid = fattr->uid;
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
344
345
346
347
  		else if (nfs_server_capable(inode, NFS_CAP_OWNER))
  			nfsi->cache_validity |= NFS_INO_INVALID_ATTR
  				| NFS_INO_INVALID_ACCESS
  				| NFS_INO_INVALID_ACL;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
348
349
  		if (fattr->valid & NFS_ATTR_FATTR_GROUP)
  			inode->i_gid = fattr->gid;
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
350
351
352
353
  		else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP))
  			nfsi->cache_validity |= NFS_INO_INVALID_ATTR
  				| NFS_INO_INVALID_ACCESS
  				| NFS_INO_INVALID_ACL;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
354
355
356
  		if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
  			inode->i_blocks = fattr->du.nfs2.blocks;
  		if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
  			/*
  			 * report the blocks in 512byte units
  			 */
  			inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
  		}
  		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
b0c4fddca   Trond Myklebust   NFS: Cleanup - av...
363
  		nfsi->attrtimeo_timestamp = now;
1c3c07e9f   Trond Myklebust   NFS: Add a new AC...
364
  		nfsi->access_cache = RB_ROOT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365

ef79c097b   David Howells   NFS: Use local di...
366
  		nfs_fscache_init_inode_cookie(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
371
372
373
374
375
376
377
378
379
  		unlock_new_inode(inode);
  	} else
  		nfs_refresh_inode(inode, fattr);
  	dprintk("NFS: nfs_fhget(%s/%Ld ct=%d)
  ",
  		inode->i_sb->s_id,
  		(long long)NFS_FILEID(inode),
  		atomic_read(&inode->i_count));
  
  out:
  	return inode;
  
  out_no_inode:
03f28e3a2   Trond Myklebust   NFS: Make nfs_fhg...
380
381
  	dprintk("nfs_fhget: iget failed with error %ld
  ", PTR_ERR(inode));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
383
  	goto out;
  }
659bfcd6d   Trond Myklebust   NFS: Fix the ftru...
384
  #define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
388
389
  
  int
  nfs_setattr(struct dentry *dentry, struct iattr *attr)
  {
  	struct inode *inode = dentry->d_inode;
987f8dfc9   Trond Myklebust   NFS: Reduce stack...
390
391
  	struct nfs_fattr *fattr;
  	int error = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392

91d5b4702   Chuck Lever   NFS: add I/O perf...
393
  	nfs_inc_stats(inode, NFSIOS_VFSSETATTR);
188b95dd8   Jeff Layton   NFS: if ATTR_KILL...
394
395
396
  	/* skip mode change if it's just for clearing setuid/setgid */
  	if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
  		attr->ia_valid &= ~ATTR_MODE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
400
401
402
403
  	if (attr->ia_valid & ATTR_SIZE) {
  		if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode))
  			attr->ia_valid &= ~ATTR_SIZE;
  	}
  
  	/* Optimization: if the end result is no change, don't RPC */
  	attr->ia_valid &= NFS_VALID_ATTRS;
659bfcd6d   Trond Myklebust   NFS: Fix the ftru...
404
  	if ((attr->ia_valid & ~ATTR_FILE) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  		return 0;
755c1e20c   Trond Myklebust   NFS: writes shoul...
406
  	/* Write all dirty data */
1b924e5f8   Trond Myklebust   NFS: Clean up the...
407
  	if (S_ISREG(inode->i_mode))
e1552e199   Trond Myklebust   NFS: Fix an Oops ...
408
  		nfs_wb_all(inode);
987f8dfc9   Trond Myklebust   NFS: Reduce stack...
409
410
411
412
  
  	fattr = nfs_alloc_fattr();
  	if (fattr == NULL)
  		goto out;
642ac5492   Trond Myklebust   NFSv4: Return del...
413
414
415
416
417
  	/*
  	 * Return any delegations if we're going to change ACLs
  	 */
  	if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0)
  		nfs_inode_return_delegation(inode);
987f8dfc9   Trond Myklebust   NFS: Reduce stack...
418
  	error = NFS_PROTO(inode)->setattr(dentry, fattr, attr);
65e4308d2   Trond Myklebust   [PATCH] NFS: Ensu...
419
  	if (error == 0)
987f8dfc9   Trond Myklebust   NFS: Reduce stack...
420
421
422
  		nfs_refresh_inode(inode, fattr);
  	nfs_free_fattr(fattr);
  out:
65e4308d2   Trond Myklebust   [PATCH] NFS: Ensu...
423
424
425
426
  	return error;
  }
  
  /**
a3d01454b   Trond Myklebust   NFS: Remove BKL r...
427
428
429
430
431
432
433
434
435
436
   * nfs_vmtruncate - unmap mappings "freed" by truncate() syscall
   * @inode: inode of the file used
   * @offset: file offset to start truncating
   *
   * This is a copy of the common vmtruncate, but with the locking
   * corrected to take into account the fact that NFS requires
   * inode->i_size to be updated under the inode->i_lock.
   */
  static int nfs_vmtruncate(struct inode * inode, loff_t offset)
  {
c08d3b0e3   npiggin@suse.de   truncate: use new...
437
438
  	loff_t oldsize;
  	int err;
a3d01454b   Trond Myklebust   NFS: Remove BKL r...
439

c08d3b0e3   npiggin@suse.de   truncate: use new...
440
441
442
  	err = inode_newsize_ok(inode, offset);
  	if (err)
  		goto out;
a3d01454b   Trond Myklebust   NFS: Remove BKL r...
443

c08d3b0e3   npiggin@suse.de   truncate: use new...
444
445
446
447
448
449
450
451
  	spin_lock(&inode->i_lock);
  	oldsize = inode->i_size;
  	i_size_write(inode, offset);
  	spin_unlock(&inode->i_lock);
  
  	truncate_pagecache(inode, oldsize, offset);
  out:
  	return err;
a3d01454b   Trond Myklebust   NFS: Remove BKL r...
452
453
454
  }
  
  /**
65e4308d2   Trond Myklebust   [PATCH] NFS: Ensu...
455
456
457
458
459
460
461
462
463
464
   * nfs_setattr_update_inode - Update inode metadata after a setattr call.
   * @inode: pointer to struct inode
   * @attr: pointer to struct iattr
   *
   * Note: we do this in the *proc.c in order to ensure that
   *       it works for things like exclusive creates too.
   */
  void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
  {
  	if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
2f28ea614   Trond Myklebust   NFS: Fix up nfs_s...
465
  		spin_lock(&inode->i_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
  		if ((attr->ia_valid & ATTR_MODE) != 0) {
65e4308d2   Trond Myklebust   [PATCH] NFS: Ensu...
467
468
  			int mode = attr->ia_mode & S_IALLUGO;
  			mode |= inode->i_mode & ~S_IALLUGO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
471
472
473
474
  			inode->i_mode = mode;
  		}
  		if ((attr->ia_valid & ATTR_UID) != 0)
  			inode->i_uid = attr->ia_uid;
  		if ((attr->ia_valid & ATTR_GID) != 0)
  			inode->i_gid = attr->ia_gid;
552968098   Chuck Lever   [PATCH] NFS: spli...
475
  		NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
dc59250c6   Chuck Lever   [PATCH] NFS: Intr...
476
  		spin_unlock(&inode->i_lock);
65e4308d2   Trond Myklebust   [PATCH] NFS: Ensu...
477
478
  	}
  	if ((attr->ia_valid & ATTR_SIZE) != 0) {
91d5b4702   Chuck Lever   NFS: add I/O perf...
479
  		nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
a3d01454b   Trond Myklebust   NFS: Remove BKL r...
480
  		nfs_vmtruncate(inode, attr->ia_size);
65e4308d2   Trond Myklebust   [PATCH] NFS: Ensu...
481
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
  int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
  {
  	struct inode *inode = dentry->d_inode;
552968098   Chuck Lever   [PATCH] NFS: spli...
486
  	int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  	int err;
acdc53b21   Trond Myklebust   NFS: Replace __nf...
488
  	/* Flush out writes to the server in order to update c/mtime.  */
28c494c5c   Chuck Lever   NFS: Prevent nfs_...
489
  	if (S_ISREG(inode->i_mode)) {
acdc53b21   Trond Myklebust   NFS: Replace __nf...
490
491
492
  		err = filemap_write_and_wait(inode->i_mapping);
  		if (err)
  			goto out;
28c494c5c   Chuck Lever   NFS: Prevent nfs_...
493
  	}
fc33a7bb9   Christoph Hellwig   [PATCH] per-mount...
494
495
496
497
498
499
500
501
502
503
504
505
  
  	/*
  	 * We may force a getattr if the user cares about atime.
  	 *
  	 * Note that we only have to check the vfsmount flags here:
  	 *  - NFS always sets S_NOATIME by so checking it would give a
  	 *    bogus result
  	 *  - NFS never sets MS_NOATIME or MS_NODIRATIME so there is
  	 *    no point in checking those.
  	 */
   	if ((mnt->mnt_flags & MNT_NOATIME) ||
   	    ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  		need_atime = 0;
fc33a7bb9   Christoph Hellwig   [PATCH] per-mount...
507

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
  	if (need_atime)
  		err = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
  	else
  		err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
4e769b934   Peter Staubach   64 bit ino suppor...
512
  	if (!err) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  		generic_fillattr(inode, stat);
f43bf0beb   Trond Myklebust   NFS: Add a boot p...
514
  		stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
4e769b934   Peter Staubach   64 bit ino suppor...
515
  	}
acdc53b21   Trond Myklebust   NFS: Replace __nf...
516
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
  	return err;
  }
f11ac8db5   Trond Myklebust   NFSv4: Ensure tha...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
  static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
  {
  	atomic_set(&l_ctx->count, 1);
  	l_ctx->lockowner = current->files;
  	l_ctx->pid = current->tgid;
  	INIT_LIST_HEAD(&l_ctx->list);
  }
  
  static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx)
  {
  	struct nfs_lock_context *pos;
  
  	list_for_each_entry(pos, &ctx->lock_context.list, list) {
  		if (pos->lockowner != current->files)
  			continue;
  		if (pos->pid != current->tgid)
  			continue;
  		atomic_inc(&pos->count);
  		return pos;
  	}
  	return NULL;
  }
  
  struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)
  {
  	struct nfs_lock_context *res, *new = NULL;
3d4ff43d8   Al Viro   nfs_open_context ...
545
  	struct inode *inode = ctx->dentry->d_inode;
f11ac8db5   Trond Myklebust   NFSv4: Ensure tha...
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
  
  	spin_lock(&inode->i_lock);
  	res = __nfs_find_lock_context(ctx);
  	if (res == NULL) {
  		spin_unlock(&inode->i_lock);
  		new = kmalloc(sizeof(*new), GFP_KERNEL);
  		if (new == NULL)
  			return NULL;
  		nfs_init_lock_context(new);
  		spin_lock(&inode->i_lock);
  		res = __nfs_find_lock_context(ctx);
  		if (res == NULL) {
  			list_add_tail(&new->list, &ctx->lock_context.list);
  			new->open_context = ctx;
  			res = new;
  			new = NULL;
  		}
  	}
  	spin_unlock(&inode->i_lock);
  	kfree(new);
  	return res;
  }
  
  void nfs_put_lock_context(struct nfs_lock_context *l_ctx)
  {
  	struct nfs_open_context *ctx = l_ctx->open_context;
3d4ff43d8   Al Viro   nfs_open_context ...
572
  	struct inode *inode = ctx->dentry->d_inode;
f11ac8db5   Trond Myklebust   NFSv4: Ensure tha...
573
574
575
576
577
578
579
  
  	if (!atomic_dec_and_lock(&l_ctx->count, &inode->i_lock))
  		return;
  	list_del(&l_ctx->list);
  	spin_unlock(&inode->i_lock);
  	kfree(l_ctx);
  }
7fe5c398f   Trond Myklebust   NFS: Optimise NFS...
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
  /**
   * nfs_close_context - Common close_context() routine NFSv2/v3
   * @ctx: pointer to context
   * @is_sync: is this a synchronous close
   *
   * always ensure that the attributes are up to date if we're mounted
   * with close-to-open semantics
   */
  void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
  {
  	struct inode *inode;
  	struct nfs_server *server;
  
  	if (!(ctx->mode & FMODE_WRITE))
  		return;
  	if (!is_sync)
  		return;
3d4ff43d8   Al Viro   nfs_open_context ...
597
  	inode = ctx->dentry->d_inode;
7fe5c398f   Trond Myklebust   NFS: Optimise NFS...
598
599
600
601
602
603
604
  	if (!list_empty(&NFS_I(inode)->open_files))
  		return;
  	server = NFS_SERVER(inode);
  	if (server->flags & NFS_MOUNT_NOCTO)
  		return;
  	nfs_revalidate_inode(server, inode);
  }
5ede7b1cf   Al Viro   pull manipulation...
605
  struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, fmode_t f_mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
  {
  	struct nfs_open_context *ctx;
5ede7b1cf   Al Viro   pull manipulation...
608
609
610
  	struct rpc_cred *cred = rpc_lookup_cred();
  	if (IS_ERR(cred))
  		return ERR_CAST(cred);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611

f52720ca5   Panagiotis Issaris   [PATCH] fs: Remov...
612
  	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
5ede7b1cf   Al Viro   pull manipulation...
613
614
615
  	if (!ctx) {
  		put_rpccred(cred);
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
  	}
5ede7b1cf   Al Viro   pull manipulation...
617
618
619
620
621
622
623
624
625
626
  	nfs_sb_active(dentry->d_sb);
  	ctx->dentry = dget(dentry);
  	ctx->cred = cred;
  	ctx->state = NULL;
  	ctx->mode = f_mode;
  	ctx->flags = 0;
  	ctx->error = 0;
  	nfs_init_lock_context(&ctx->lock_context);
  	ctx->lock_context.open_context = ctx;
  	INIT_LIST_HEAD(&ctx->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
630
631
632
  	return ctx;
  }
  
  struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
  {
  	if (ctx != NULL)
f11ac8db5   Trond Myklebust   NFSv4: Ensure tha...
633
  		atomic_inc(&ctx->lock_context.count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
  	return ctx;
  }
7fe5c398f   Trond Myklebust   NFS: Optimise NFS...
636
  static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
  {
3d4ff43d8   Al Viro   nfs_open_context ...
638
639
  	struct inode *inode = ctx->dentry->d_inode;
  	struct super_block *sb = ctx->dentry->d_sb;
3bec63db5   Trond Myklebust   NFS: Convert stru...
640

5c78f58e2   Trond Myklebust   NFS: Really fix p...
641
  	if (!list_empty(&ctx->list)) {
ef84303eb   Benny Halevy   NFS: handle inode...
642
643
644
645
  		if (!atomic_dec_and_lock(&ctx->lock_context.count, &inode->i_lock))
  			return;
  		list_del(&ctx->list);
  		spin_unlock(&inode->i_lock);
ef84303eb   Benny Halevy   NFS: handle inode...
646
  	} else if (!atomic_dec_and_test(&ctx->lock_context.count))
5e11934d1   Trond Myklebust   NFS: Fix put_nfs_...
647
  		return;
5c78f58e2   Trond Myklebust   NFS: Really fix p...
648
649
  	if (inode != NULL)
  		NFS_PROTO(inode)->close_context(ctx, is_sync);
3bec63db5   Trond Myklebust   NFS: Convert stru...
650
651
  	if (ctx->cred != NULL)
  		put_rpccred(ctx->cred);
3d4ff43d8   Al Viro   nfs_open_context ...
652
653
  	dput(ctx->dentry);
  	nfs_sb_deactive(sb);
3bec63db5   Trond Myklebust   NFS: Convert stru...
654
655
  	kfree(ctx);
  }
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
656
657
658
659
  void put_nfs_open_context(struct nfs_open_context *ctx)
  {
  	__put_nfs_open_context(ctx, 0);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
661
662
663
  /*
   * Ensure that mmap has a recent RPC credential for use when writing out
   * shared pages
   */
cd9a1c0e5   Trond Myklebust   NFSv4: Clean up n...
664
  void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  {
01cce933d   Josef "Jeff" Sipek   [PATCH] nfs: chan...
666
  	struct inode *inode = filp->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
669
670
671
672
673
  	struct nfs_inode *nfsi = NFS_I(inode);
  
  	filp->private_data = get_nfs_open_context(ctx);
  	spin_lock(&inode->i_lock);
  	list_add(&ctx->list, &nfsi->open_files);
  	spin_unlock(&inode->i_lock);
  }
d530838bf   Trond Myklebust   NFSv4: Fix proble...
674
675
676
  /*
   * Given an inode, search for an open context with the desired characteristics
   */
dc0b027df   Trond Myklebust   NFSv4: Convert th...
677
  struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
679
680
681
682
683
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
  	struct nfs_open_context *pos, *ctx = NULL;
  
  	spin_lock(&inode->i_lock);
  	list_for_each_entry(pos, &nfsi->open_files, list) {
d530838bf   Trond Myklebust   NFSv4: Fix proble...
684
685
  		if (cred != NULL && pos->cred != cred)
  			continue;
1544fa0f7   Trond Myklebust   NFS: Fix the mode...
686
687
688
689
  		if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode)
  			continue;
  		ctx = get_nfs_open_context(pos);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690
691
692
693
  	}
  	spin_unlock(&inode->i_lock);
  	return ctx;
  }
b92dccf65   Trond Myklebust   NFS: Fix a busy i...
694
  static void nfs_file_clear_open_context(struct file *filp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  {
01cce933d   Josef "Jeff" Sipek   [PATCH] nfs: chan...
696
  	struct inode *inode = filp->f_path.dentry->d_inode;
cd3758e37   Trond Myklebust   NFS: Replace file...
697
  	struct nfs_open_context *ctx = nfs_file_open_context(filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
703
  
  	if (ctx) {
  		filp->private_data = NULL;
  		spin_lock(&inode->i_lock);
  		list_move_tail(&ctx->list, &NFS_I(inode)->open_files);
  		spin_unlock(&inode->i_lock);
f895c53f8   Chuck Lever   NFS: Make close(2...
704
  		__put_nfs_open_context(ctx, filp->f_flags & O_DIRECT ? 0 : 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
707
708
709
710
711
712
713
  	}
  }
  
  /*
   * These allocate and release file read/write context information.
   */
  int nfs_open(struct inode *inode, struct file *filp)
  {
  	struct nfs_open_context *ctx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714

5ede7b1cf   Al Viro   pull manipulation...
715
716
717
  	ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode);
  	if (IS_ERR(ctx))
  		return PTR_ERR(ctx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
719
  	nfs_file_set_open_context(filp, ctx);
  	put_nfs_open_context(ctx);
ef79c097b   David Howells   NFS: Use local di...
720
  	nfs_fscache_set_inode_cookie(inode, filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
723
724
725
  	return 0;
  }
  
  int nfs_release(struct inode *inode, struct file *filp)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
727
728
729
730
731
732
733
734
735
736
737
  	nfs_file_clear_open_context(filp);
  	return 0;
  }
  
  /*
   * This function is called whenever some part of NFS notices that
   * the cached attributes have to be refreshed.
   */
  int
  __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
  {
  	int		 status = -ESTALE;
a3cba2aad   Trond Myklebust   NFS: Reduce stack...
738
  	struct nfs_fattr *fattr = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
739
  	struct nfs_inode *nfsi = NFS_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
743
  
  	dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)
  ",
  		inode->i_sb->s_id, (long long)NFS_FILEID(inode));
85233a7a4   Chuck Lever   [PATCH] NFS: __nf...
744
  	if (is_bad_inode(inode))
691beb13c   Trond Myklebust   NFS: Allow concur...
745
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
  	if (NFS_STALE(inode))
412d582ec   Chuck Lever   [PATCH] NFS: use ...
747
  		goto out;
7fdc49c4e   Trond Myklebust   NFS: Fix the ESTA...
748

a3cba2aad   Trond Myklebust   NFS: Reduce stack...
749
750
751
752
  	status = -ENOMEM;
  	fattr = nfs_alloc_fattr();
  	if (fattr == NULL)
  		goto out;
691beb13c   Trond Myklebust   NFS: Allow concur...
753
  	nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
a3cba2aad   Trond Myklebust   NFS: Reduce stack...
754
  	status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
757
758
759
760
761
762
  	if (status != 0) {
  		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d
  ",
  			 inode->i_sb->s_id,
  			 (long long)NFS_FILEID(inode), status);
  		if (status == -ESTALE) {
  			nfs_zap_caches(inode);
  			if (!S_ISDIR(inode->i_mode))
3a10c30ac   Benny Halevy   nfs: obliterate N...
763
  				set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
766
  		}
  		goto out;
  	}
a3cba2aad   Trond Myklebust   NFS: Reduce stack...
767
  	status = nfs_refresh_inode(inode, fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
769
770
771
772
773
774
  	if (status) {
  		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d
  ",
  			 inode->i_sb->s_id,
  			 (long long)NFS_FILEID(inode), status);
  		goto out;
  	}
552968098   Chuck Lever   [PATCH] NFS: spli...
775

24aa1fe67   Trond Myklebust   NFS: Fix a few fu...
776
  	if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
ada70d942   Trond Myklebust   [PATCH] NFS: Add ...
777
  		nfs_zap_acl_cache(inode);
552968098   Chuck Lever   [PATCH] NFS: spli...
778

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
781
782
  	dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete
  ",
  		inode->i_sb->s_id,
  		(long long)NFS_FILEID(inode));
412d582ec   Chuck Lever   [PATCH] NFS: use ...
783
   out:
a3cba2aad   Trond Myklebust   NFS: Reduce stack...
784
  	nfs_free_fattr(fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
787
788
789
790
  	return status;
  }
  
  int nfs_attribute_timeout(struct inode *inode)
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
d7cf8dd01   Trond Myklebust   NFSv4: Allow attr...
791
792
793
794
795
  	return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
  }
  
  static int nfs_attribute_cache_expired(struct inode *inode)
  {
b4d2314bb   Trond Myklebust   NFSv4: Don't igno...
796
  	if (nfs_have_delegated_attributes(inode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
  		return 0;
d7cf8dd01   Trond Myklebust   NFSv4: Allow attr...
798
  	return nfs_attribute_timeout(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
801
802
803
804
805
806
807
808
809
  }
  
  /**
   * nfs_revalidate_inode - Revalidate the inode attributes
   * @server - pointer to nfs_server struct
   * @inode - pointer to inode struct
   *
   * Updates inode attribute information by retrieving the data from the server.
   */
  int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
  {
44b11874f   Trond Myklebust   NFS: Separate met...
810
  	if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR)
d7cf8dd01   Trond Myklebust   NFSv4: Allow attr...
811
  			&& !nfs_attribute_cache_expired(inode))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812
813
814
  		return NFS_STALE(inode) ? -ESTALE : 0;
  	return __nfs_revalidate_inode(server, inode);
  }
1cda707d5   Trond Myklebust   NFS: Remove requi...
815
  static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
717d44e84   Trond Myklebust   [PATCH] NFS: Fix ...
816
817
818
819
820
821
822
823
824
825
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
  	
  	if (mapping->nrpages != 0) {
  		int ret = invalidate_inode_pages2(mapping);
  		if (ret < 0)
  			return ret;
  	}
  	spin_lock(&inode->i_lock);
  	nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
2f78e4313   Trond Myklebust   NFS: Don't set ca...
826
  	if (S_ISDIR(inode->i_mode))
717d44e84   Trond Myklebust   [PATCH] NFS: Fix ...
827
  		memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
717d44e84   Trond Myklebust   [PATCH] NFS: Fix ...
828
829
  	spin_unlock(&inode->i_lock);
  	nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
ef79c097b   David Howells   NFS: Use local di...
830
  	nfs_fscache_reset_inode_cookie(inode);
717d44e84   Trond Myklebust   [PATCH] NFS: Fix ...
831
832
833
834
835
  	dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated
  ",
  			inode->i_sb->s_id, (long long)NFS_FILEID(inode));
  	return 0;
  }
717d44e84   Trond Myklebust   [PATCH] NFS: Fix ...
836
837
838
839
  /**
   * nfs_revalidate_mapping - Revalidate the pagecache
   * @inode - pointer to host inode
   * @mapping - pointer to mapping
717d44e84   Trond Myklebust   [PATCH] NFS: Fix ...
840
841
842
843
844
   */
  int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
  	int ret = 0;
dc59250c6   Chuck Lever   [PATCH] NFS: Intr...
845

717d44e84   Trond Myklebust   [PATCH] NFS: Fix ...
846
  	if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
d7cf8dd01   Trond Myklebust   NFSv4: Allow attr...
847
848
  			|| nfs_attribute_cache_expired(inode)
  			|| NFS_STALE(inode)) {
717d44e84   Trond Myklebust   [PATCH] NFS: Fix ...
849
850
851
  		ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
  		if (ret < 0)
  			goto out;
7d52e8627   Trond Myklebust   [PATCH] NFS: Clea...
852
  	}
717d44e84   Trond Myklebust   [PATCH] NFS: Fix ...
853
854
  	if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
  		ret = nfs_invalidate_mapping(inode, mapping);
cd9ae2b6a   Trond Myklebust   [PATCH] NFS: Deal...
855
  out:
44b11874f   Trond Myklebust   NFS: Separate met...
856
  	return ret;
7d52e8627   Trond Myklebust   [PATCH] NFS: Clea...
857
  }
27dc1cd3a   Trond Myklebust   NFS: nfs_wcc_upda...
858
  static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
a895b4a19   Trond Myklebust   NFS: Clean up wea...
859
860
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
27dc1cd3a   Trond Myklebust   NFS: nfs_wcc_upda...
861
  	unsigned long ret = 0;
a895b4a19   Trond Myklebust   NFS: Clean up wea...
862

9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
863
864
  	if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
  			&& (fattr->valid & NFS_ATTR_FATTR_CHANGE)
a9a4a87a5   Trond Myklebust   NFS: Use the inod...
865
866
  			&& inode->i_version == fattr->pre_change_attr) {
  		inode->i_version = fattr->change_attr;
70ca88521   Trond Myklebust   NFS: Fake up 'wcc...
867
868
  		if (S_ISDIR(inode->i_mode))
  			nfsi->cache_validity |= NFS_INO_INVALID_DATA;
27dc1cd3a   Trond Myklebust   NFS: nfs_wcc_upda...
869
  		ret |= NFS_INO_INVALID_ATTR;
70ca88521   Trond Myklebust   NFS: Fake up 'wcc...
870
  	}
a895b4a19   Trond Myklebust   NFS: Clean up wea...
871
  	/* If we have atomic WCC data, we may update some attributes */
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
872
873
  	if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME)
  			&& (fattr->valid & NFS_ATTR_FATTR_CTIME)
27dc1cd3a   Trond Myklebust   NFS: nfs_wcc_upda...
874
875
876
877
  			&& timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) {
  		memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
  		ret |= NFS_INO_INVALID_ATTR;
  	}
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
878
879
880
881
  
  	if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME)
  			&& (fattr->valid & NFS_ATTR_FATTR_MTIME)
  			&& timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
27dc1cd3a   Trond Myklebust   NFS: nfs_wcc_upda...
882
883
884
885
  		memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
  		if (S_ISDIR(inode->i_mode))
  			nfsi->cache_validity |= NFS_INO_INVALID_DATA;
  		ret |= NFS_INO_INVALID_ATTR;
a895b4a19   Trond Myklebust   NFS: Clean up wea...
886
  	}
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
887
888
889
  	if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
  			&& (fattr->valid & NFS_ATTR_FATTR_SIZE)
  			&& i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
27dc1cd3a   Trond Myklebust   NFS: nfs_wcc_upda...
890
891
892
893
894
  			&& nfsi->npages == 0) {
  		i_size_write(inode, nfs_size_to_loff_t(fattr->size));
  		ret |= NFS_INO_INVALID_ATTR;
  	}
  	return ret;
a895b4a19   Trond Myklebust   NFS: Clean up wea...
895
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
  /**
33801147a   Trond Myklebust   NFS: Optimise ino...
897
   * nfs_check_inode_attributes - verify consistency of the inode attribute cache
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
900
901
902
903
904
   * @inode - pointer to inode
   * @fattr - updated attributes
   *
   * Verifies the attribute cache. If we have just changed the attributes,
   * so that fattr carries weak cache consistency data, then it may
   * also update the ctime/mtime/change_attribute.
   */
33801147a   Trond Myklebust   NFS: Optimise ino...
905
  static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fattr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
908
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
  	loff_t cur_size, new_isize;
2a3f5fd45   Trond Myklebust   NFS: nfs_refresh_...
909
  	unsigned long invalid = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910

dc59250c6   Chuck Lever   [PATCH] NFS: Intr...
911

ca62b9c3f   Trond Myklebust   NFSv4: Don't inva...
912
  	/* Has the inode gone and changed behind our back? */
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
913
914
915
  	if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
  		return -EIO;
  	if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
ca62b9c3f   Trond Myklebust   NFSv4: Don't inva...
916
  		return -EIO;
ca62b9c3f   Trond Myklebust   NFSv4: Don't inva...
917

9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
918
  	if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
a9a4a87a5   Trond Myklebust   NFS: Use the inod...
919
  			inode->i_version != fattr->change_attr)
2a3f5fd45   Trond Myklebust   NFS: nfs_refresh_...
920
  		invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
  	/* Verify a few of the more important attributes */
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
923
  	if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&inode->i_mtime, &fattr->mtime))
2a3f5fd45   Trond Myklebust   NFS: nfs_refresh_...
924
  		invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
ca62b9c3f   Trond Myklebust   NFSv4: Don't inva...
925

9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
926
927
928
929
930
931
  	if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
  		cur_size = i_size_read(inode);
  		new_isize = nfs_size_to_loff_t(fattr->size);
  		if (cur_size != new_isize && nfsi->npages == 0)
  			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
  
  	/* Have any file permissions changed? */
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
934
935
936
937
938
  	if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
  		invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
  	if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && inode->i_uid != fattr->uid)
  		invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
  	if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && inode->i_gid != fattr->gid)
2a3f5fd45   Trond Myklebust   NFS: nfs_refresh_...
939
  		invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
  
  	/* Has the link count changed? */
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
942
  	if ((fattr->valid & NFS_ATTR_FATTR_NLINK) && inode->i_nlink != fattr->nlink)
2a3f5fd45   Trond Myklebust   NFS: nfs_refresh_...
943
  		invalid |= NFS_INO_INVALID_ATTR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944

9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
945
  	if ((fattr->valid & NFS_ATTR_FATTR_ATIME) && !timespec_equal(&inode->i_atime, &fattr->atime))
2a3f5fd45   Trond Myklebust   NFS: nfs_refresh_...
946
947
948
949
  		invalid |= NFS_INO_INVALID_ATIME;
  
  	if (invalid != 0)
  		nfsi->cache_validity |= invalid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950

33801147a   Trond Myklebust   NFS: Optimise ino...
951
  	nfsi->read_cache_jiffies = fattr->time_start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
  	return 0;
  }
a10ad1763   Trond Myklebust   NFS: Fix the NFS ...
954
  static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
870a5be8b   Trond Myklebust   NFS: Clean up nfs...
955
  {
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
956
957
  	if (!(fattr->valid & NFS_ATTR_FATTR_CTIME))
  		return 0;
a10ad1763   Trond Myklebust   NFS: Fix the NFS ...
958
959
960
961
962
  	return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0;
  }
  
  static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
  {
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
963
964
  	if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
  		return 0;
a10ad1763   Trond Myklebust   NFS: Fix the NFS ...
965
966
  	return nfs_size_to_loff_t(fattr->size) > i_size_read(inode);
  }
870a5be8b   Trond Myklebust   NFS: Clean up nfs...
967

ae05f2694   Trond Myklebust   NFS: Convert nfs_...
968
  static atomic_long_t nfs_attr_generation_counter;
4704f0e27   Trond Myklebust   NFS: Fix the reso...
969
970
971
  
  static unsigned long nfs_read_attr_generation_counter(void)
  {
ae05f2694   Trond Myklebust   NFS: Convert nfs_...
972
  	return atomic_long_read(&nfs_attr_generation_counter);
4704f0e27   Trond Myklebust   NFS: Fix the reso...
973
974
975
976
  }
  
  unsigned long nfs_inc_attr_generation_counter(void)
  {
ae05f2694   Trond Myklebust   NFS: Convert nfs_...
977
  	return atomic_long_inc_return(&nfs_attr_generation_counter);
4704f0e27   Trond Myklebust   NFS: Fix the reso...
978
979
980
981
982
983
984
  }
  
  void nfs_fattr_init(struct nfs_fattr *fattr)
  {
  	fattr->valid = 0;
  	fattr->time_start = jiffies;
  	fattr->gencount = nfs_inc_attr_generation_counter();
6926afd19   Trond Myklebust   NFSv4: Save the o...
985
986
  	fattr->owner_name = NULL;
  	fattr->group_name = NULL;
4704f0e27   Trond Myklebust   NFS: Fix the reso...
987
  }
2d36bfde8   Trond Myklebust   NFS: Add helper f...
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
  struct nfs_fattr *nfs_alloc_fattr(void)
  {
  	struct nfs_fattr *fattr;
  
  	fattr = kmalloc(sizeof(*fattr), GFP_NOFS);
  	if (fattr != NULL)
  		nfs_fattr_init(fattr);
  	return fattr;
  }
  
  struct nfs_fh *nfs_alloc_fhandle(void)
  {
  	struct nfs_fh *fh;
  
  	fh = kmalloc(sizeof(struct nfs_fh), GFP_NOFS);
  	if (fh != NULL)
  		fh->size = 0;
  	return fh;
  }
a10ad1763   Trond Myklebust   NFS: Fix the NFS ...
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
  /**
   * nfs_inode_attrs_need_update - check if the inode attributes need updating
   * @inode - pointer to inode
   * @fattr - attributes
   *
   * Attempt to divine whether or not an RPC call reply carrying stale
   * attributes got scheduled after another call carrying updated ones.
   *
   * To do so, the function first assumes that a more recent ctime means
   * that the attributes in fattr are newer, however it also attempt to
   * catch the case where ctime either didn't change, or went backwards
   * (if someone reset the clock on the server) by looking at whether
   * or not this RPC call was started after the inode was last updated.
4704f0e27   Trond Myklebust   NFS: Fix the reso...
1020
   * Note also the check for wraparound of 'attr_gencount'
a10ad1763   Trond Myklebust   NFS: Fix the NFS ...
1021
1022
1023
1024
1025
1026
1027
1028
   *
   * The function returns 'true' if it thinks the attributes in 'fattr' are
   * more recent than the ones cached in the inode.
   *
   */
  static int nfs_inode_attrs_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
  {
  	const struct nfs_inode *nfsi = NFS_I(inode);
4704f0e27   Trond Myklebust   NFS: Fix the reso...
1029
  	return ((long)fattr->gencount - (long)nfsi->attr_gencount) > 0 ||
03254e65a   Trond Myklebust   NFS: Fix attribut...
1030
1031
  		nfs_ctime_need_update(inode, fattr) ||
  		nfs_size_need_update(inode, fattr) ||
4704f0e27   Trond Myklebust   NFS: Fix the reso...
1032
  		((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
a10ad1763   Trond Myklebust   NFS: Fix the NFS ...
1033
1034
1035
1036
1037
  }
  
  static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
  {
  	if (nfs_inode_attrs_need_update(inode, fattr))
870a5be8b   Trond Myklebust   NFS: Clean up nfs...
1038
1039
1040
  		return nfs_update_inode(inode, fattr);
  	return nfs_check_inode_attributes(inode, fattr);
  }
33801147a   Trond Myklebust   NFS: Optimise ino...
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
  /**
   * nfs_refresh_inode - try to update the inode attribute cache
   * @inode - pointer to inode
   * @fattr - updated attributes
   *
   * Check that an RPC call that returned attributes has not overlapped with
   * other recent updates of the inode metadata, then decide whether it is
   * safe to do a full update of the inode attributes, or whether just to
   * call nfs_check_inode_attributes.
   */
  int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
  {
33801147a   Trond Myklebust   NFS: Optimise ino...
1053
1054
1055
1056
1057
  	int status;
  
  	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
  		return 0;
  	spin_lock(&inode->i_lock);
870a5be8b   Trond Myklebust   NFS: Clean up nfs...
1058
  	status = nfs_refresh_inode_locked(inode, fattr);
33801147a   Trond Myklebust   NFS: Optimise ino...
1059
  	spin_unlock(&inode->i_lock);
ef79c097b   David Howells   NFS: Use local di...
1060

33801147a   Trond Myklebust   NFS: Optimise ino...
1061
1062
  	return status;
  }
d65f557f3   Trond Myklebust   NFS: Fix nfs_post...
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
  static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
  
  	nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
  	if (S_ISDIR(inode->i_mode))
  		nfsi->cache_validity |= NFS_INO_INVALID_DATA;
  	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
  		return 0;
  	return nfs_refresh_inode_locked(inode, fattr);
  }
decf491f3   Trond Myklebust   NFS: Don't let nf...
1074
1075
1076
1077
1078
1079
1080
  /**
   * nfs_post_op_update_inode - try to update the inode attribute cache
   * @inode - pointer to inode
   * @fattr - updated attributes
   *
   * After an operation that has changed the inode metadata, mark the
   * attribute cache as being invalid, then try to update it.
f551e44ff   Chuck Lever   NFS: add comments...
1081
1082
1083
1084
1085
1086
   *
   * NB: if the server didn't return any post op attributes, this
   * function will force the retrieval of attributes before the next
   * NFS request.  Thus it should be used only for operations that
   * are expected to change one or more attributes, to avoid
   * unnecessary NFS requests and trips through nfs_update_inode().
decf491f3   Trond Myklebust   NFS: Don't let nf...
1087
1088
1089
   */
  int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
  {
d65f557f3   Trond Myklebust   NFS: Fix nfs_post...
1090
  	int status;
decf491f3   Trond Myklebust   NFS: Don't let nf...
1091

7668fdbe9   Trond Myklebust   NFS: nfs_post_op_...
1092
  	spin_lock(&inode->i_lock);
d65f557f3   Trond Myklebust   NFS: Fix nfs_post...
1093
  	status = nfs_post_op_update_inode_locked(inode, fattr);
7668fdbe9   Trond Myklebust   NFS: nfs_post_op_...
1094
  	spin_unlock(&inode->i_lock);
870a5be8b   Trond Myklebust   NFS: Clean up nfs...
1095
  	return status;
decf491f3   Trond Myklebust   NFS: Don't let nf...
1096
  }
70ca88521   Trond Myklebust   NFS: Fake up 'wcc...
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
  /**
   * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
   * @inode - pointer to inode
   * @fattr - updated attributes
   *
   * After an operation that has changed the inode metadata, mark the
   * attribute cache as being invalid, then try to update it. Fake up
   * weak cache consistency data, if none exist.
   *
   * This function is mainly designed to be used by the ->write_done() functions.
   */
  int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
  {
d65f557f3   Trond Myklebust   NFS: Fix nfs_post...
1110
1111
1112
1113
1114
1115
  	int status;
  
  	spin_lock(&inode->i_lock);
  	/* Don't do a WCC update if these attributes are already stale */
  	if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
  			!nfs_inode_attrs_need_update(inode, fattr)) {
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1116
1117
1118
1119
  		fattr->valid &= ~(NFS_ATTR_FATTR_PRECHANGE
  				| NFS_ATTR_FATTR_PRESIZE
  				| NFS_ATTR_FATTR_PREMTIME
  				| NFS_ATTR_FATTR_PRECTIME);
d65f557f3   Trond Myklebust   NFS: Fix nfs_post...
1120
1121
  		goto out_noforce;
  	}
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1122
1123
  	if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
  			(fattr->valid & NFS_ATTR_FATTR_PRECHANGE) == 0) {
a9a4a87a5   Trond Myklebust   NFS: Use the inod...
1124
  		fattr->pre_change_attr = inode->i_version;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1125
  		fattr->valid |= NFS_ATTR_FATTR_PRECHANGE;
70ca88521   Trond Myklebust   NFS: Fake up 'wcc...
1126
  	}
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1127
1128
  	if ((fattr->valid & NFS_ATTR_FATTR_CTIME) != 0 &&
  			(fattr->valid & NFS_ATTR_FATTR_PRECTIME) == 0) {
70ca88521   Trond Myklebust   NFS: Fake up 'wcc...
1129
  		memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1130
1131
1132
1133
  		fattr->valid |= NFS_ATTR_FATTR_PRECTIME;
  	}
  	if ((fattr->valid & NFS_ATTR_FATTR_MTIME) != 0 &&
  			(fattr->valid & NFS_ATTR_FATTR_PREMTIME) == 0) {
70ca88521   Trond Myklebust   NFS: Fake up 'wcc...
1134
  		memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1135
1136
1137
1138
  		fattr->valid |= NFS_ATTR_FATTR_PREMTIME;
  	}
  	if ((fattr->valid & NFS_ATTR_FATTR_SIZE) != 0 &&
  			(fattr->valid & NFS_ATTR_FATTR_PRESIZE) == 0) {
a3d01454b   Trond Myklebust   NFS: Remove BKL r...
1139
  		fattr->pre_size = i_size_read(inode);
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1140
  		fattr->valid |= NFS_ATTR_FATTR_PRESIZE;
70ca88521   Trond Myklebust   NFS: Fake up 'wcc...
1141
  	}
d65f557f3   Trond Myklebust   NFS: Fix nfs_post...
1142
1143
1144
1145
  out_noforce:
  	status = nfs_post_op_update_inode_locked(inode, fattr);
  	spin_unlock(&inode->i_lock);
  	return status;
70ca88521   Trond Myklebust   NFS: Fake up 'wcc...
1146
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
  /*
   * Many nfs protocol calls return the new file attributes after
   * an operation.  Here we update the inode to reflect the state
   * of the server's inode.
   *
   * This is a bit tricky because we have to make sure all dirty pages
   * have been sent off to the server before calling invalidate_inode_pages.
   * To make sure no other process adds more write requests while we try
   * our best to flush them, we make them sleep during the attribute refresh.
   *
   * A very similar scenario holds for the dir cache.
   */
24aa1fe67   Trond Myklebust   NFS: Fix a few fu...
1159
  static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
  {
8b4bdcf89   Trond Myklebust   NFS: Store the fi...
1161
  	struct nfs_server *server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1162
  	struct nfs_inode *nfsi = NFS_I(inode);
951a143b3   Trond Myklebust   [PATCH] NFS: Fix ...
1163
  	loff_t cur_isize, new_isize;
2a3f5fd45   Trond Myklebust   NFS: nfs_refresh_...
1164
  	unsigned long invalid = 0;
3e7d950a5   Trond Myklebust   NFS: Fix a wrapar...
1165
  	unsigned long now = jiffies;
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
1166
  	unsigned long save_cache_validity;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
1168
1169
  
  	dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)
  ",
3110ff804   Harvey Harrison   nfs: replace rema...
1170
  			__func__, inode->i_sb->s_id, inode->i_ino,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
  			atomic_read(&inode->i_count), fattr->valid);
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1172
  	if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
325cfed9a   Chuck Lever   NFS: make "inode ...
1173
  		goto out_fileid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
1175
1176
1177
  
  	/*
  	 * Make sure the inode's type hasn't changed.
  	 */
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1178
  	if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1179
  		goto out_changed;
8b4bdcf89   Trond Myklebust   NFS: Store the fi...
1180
  	server = NFS_SERVER(inode);
a0356862b   Trond Myklebust   NFS: Fix nfs_reva...
1181
  	/* Update the fsid? */
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1182
  	if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) &&
c37dcd334   Trond Myklebust   NFS: Fix the fsid...
1183
  			!nfs_fsid_equal(&server->fsid, &fattr->fsid) &&
36d43a437   David Howells   NFS: Use d_automo...
1184
  			!IS_AUTOMOUNT(inode))
8b4bdcf89   Trond Myklebust   NFS: Store the fi...
1185
  		server->fsid = fattr->fsid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1186
1187
1188
  	/*
  	 * Update the read time so we don't revalidate too often.
  	 */
33801147a   Trond Myklebust   NFS: Optimise ino...
1189
  	nfsi->read_cache_jiffies = fattr->time_start;
3e7d950a5   Trond Myklebust   NFS: Fix a wrapar...
1190

62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
1191
1192
1193
1194
1195
  	save_cache_validity = nfsi->cache_validity;
  	nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
  			| NFS_INO_INVALID_ATIME
  			| NFS_INO_REVAL_FORCED
  			| NFS_INO_REVAL_PAGECACHE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196

a895b4a19   Trond Myklebust   NFS: Clean up wea...
1197
  	/* Do atomic weak cache consistency updates */
27dc1cd3a   Trond Myklebust   NFS: nfs_wcc_upda...
1198
  	invalid |= nfs_wcc_update_inode(inode, fattr);
a895b4a19   Trond Myklebust   NFS: Clean up wea...
1199

47aabaa7e   Trond Myklebust   NFSv4: Don't use ...
1200
  	/* More cache consistency checks */
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1201
  	if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
a9a4a87a5   Trond Myklebust   NFS: Use the inod...
1202
  		if (inode->i_version != fattr->change_attr) {
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1203
1204
1205
1206
1207
1208
  			dprintk("NFS: change_attr change on server for file %s/%ld
  ",
  					inode->i_sb->s_id, inode->i_ino);
  			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
  			if (S_ISDIR(inode->i_mode))
  				nfs_force_lookup_revalidate(inode);
a9a4a87a5   Trond Myklebust   NFS: Use the inod...
1209
  			inode->i_version = fattr->change_attr;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1210
  		}
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
1211
1212
  	} else if (server->caps & NFS_CAP_CHANGE_ATTR)
  		invalid |= save_cache_validity;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1213
1214
  
  	if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
47aabaa7e   Trond Myklebust   NFSv4: Don't use ...
1215
1216
1217
1218
1219
1220
  		/* NFSv2/v3: Check if the mtime agrees */
  		if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
  			dprintk("NFS: mtime change on server for file %s/%ld
  ",
  					inode->i_sb->s_id, inode->i_ino);
  			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
bfc69a456   Trond Myklebust   NFS: define a fun...
1221
1222
  			if (S_ISDIR(inode->i_mode))
  				nfs_force_lookup_revalidate(inode);
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1223
  			memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
47aabaa7e   Trond Myklebust   NFSv4: Don't use ...
1224
  		}
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
1225
1226
1227
1228
1229
  	} else if (server->caps & NFS_CAP_MTIME)
  		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
  				| NFS_INO_INVALID_DATA
  				| NFS_INO_REVAL_PAGECACHE
  				| NFS_INO_REVAL_FORCED);
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1230
  	if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
47aabaa7e   Trond Myklebust   NFSv4: Don't use ...
1231
  		/* If ctime has changed we should definitely clear access+acl caches */
37d9d76d8   NeilBrown   NFS: flush cached...
1232
  		if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) {
4704f0e27   Trond Myklebust   NFS: Fix the reso...
1233
  			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
37d9d76d8   NeilBrown   NFS: flush cached...
1234
1235
1236
1237
1238
1239
1240
  			/* and probably clear data for a directory too as utimes can cause
  			 * havoc with our cache.
  			 */
  			if (S_ISDIR(inode->i_mode)) {
  				invalid |= NFS_INO_INVALID_DATA;
  				nfs_force_lookup_revalidate(inode);
  			}
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1241
  			memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
37d9d76d8   NeilBrown   NFS: flush cached...
1242
  		}
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
1243
1244
1245
1246
1247
  	} else if (server->caps & NFS_CAP_CTIME)
  		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
  				| NFS_INO_INVALID_ACCESS
  				| NFS_INO_INVALID_ACL
  				| NFS_INO_REVAL_FORCED);
47aabaa7e   Trond Myklebust   NFSv4: Don't use ...
1248

951a143b3   Trond Myklebust   [PATCH] NFS: Fix ...
1249
  	/* Check if our cached file size is stale */
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1250
1251
1252
1253
1254
1255
  	if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
  		new_isize = nfs_size_to_loff_t(fattr->size);
  		cur_isize = i_size_read(inode);
  		if (new_isize != cur_isize) {
  			/* Do we perhaps have any outstanding writes, or has
  			 * the file grown beyond our last write? */
0f66b5984   Peng Tao   NFS41: do not upd...
1256
1257
  			if ((nfsi->npages == 0 && !test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) ||
  			     new_isize > cur_isize) {
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1258
1259
1260
  				i_size_write(inode, new_isize);
  				invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
  			}
60c16ea87   Harshula Jayasuriya   NFS: nfs_update_i...
1261
1262
1263
1264
1265
1266
1267
  			dprintk("NFS: isize change on server for file %s/%ld "
  					"(%Ld to %Ld)
  ",
  					inode->i_sb->s_id,
  					inode->i_ino,
  					(long long)cur_isize,
  					(long long)new_isize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1268
  		}
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
1269
1270
1271
1272
  	} else
  		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
  				| NFS_INO_REVAL_PAGECACHE
  				| NFS_INO_REVAL_FORCED);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1273

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274

9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1275
1276
  	if (fattr->valid & NFS_ATTR_FATTR_ATIME)
  		memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
1277
1278
1279
  	else if (server->caps & NFS_CAP_ATIME)
  		invalid |= save_cache_validity & (NFS_INO_INVALID_ATIME
  				| NFS_INO_REVAL_FORCED);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280

9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1281
1282
  	if (fattr->valid & NFS_ATTR_FATTR_MODE) {
  		if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
9b4b35134   Trond Myklebust   NFS: Don't clobbe...
1283
1284
1285
  			umode_t newmode = inode->i_mode & S_IFMT;
  			newmode |= fattr->mode & S_IALLUGO;
  			inode->i_mode = newmode;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1286
  			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1287
  		}
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
1288
1289
1290
1291
1292
  	} else if (server->caps & NFS_CAP_MODE)
  		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
  				| NFS_INO_INVALID_ACCESS
  				| NFS_INO_INVALID_ACL
  				| NFS_INO_REVAL_FORCED);
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1293
1294
1295
1296
1297
  	if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
  		if (inode->i_uid != fattr->uid) {
  			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
  			inode->i_uid = fattr->uid;
  		}
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
1298
1299
1300
1301
1302
  	} else if (server->caps & NFS_CAP_OWNER)
  		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
  				| NFS_INO_INVALID_ACCESS
  				| NFS_INO_INVALID_ACL
  				| NFS_INO_REVAL_FORCED);
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1303
1304
1305
1306
1307
  	if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
  		if (inode->i_gid != fattr->gid) {
  			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
  			inode->i_gid = fattr->gid;
  		}
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
1308
1309
1310
1311
1312
  	} else if (server->caps & NFS_CAP_OWNER_GROUP)
  		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
  				| NFS_INO_INVALID_ACCESS
  				| NFS_INO_INVALID_ACL
  				| NFS_INO_REVAL_FORCED);
921615f11   Trond Myklebust   NFS: Changes to i...
1313

9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1314
1315
1316
1317
1318
  	if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
  		if (inode->i_nlink != fattr->nlink) {
  			invalid |= NFS_INO_INVALID_ATTR;
  			if (S_ISDIR(inode->i_mode))
  				invalid |= NFS_INO_INVALID_DATA;
bfe868486   Miklos Szeredi   filesystems: add ...
1319
  			set_nlink(inode, fattr->nlink);
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1320
  		}
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
1321
1322
1323
  	} else if (server->caps & NFS_CAP_NLINK)
  		invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR
  				| NFS_INO_REVAL_FORCED);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1324

9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1325
  	if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326
1327
1328
1329
  		/*
  		 * report the blocks in 512byte units
  		 */
  		inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1330
   	}
9e6e70f8d   Trond Myklebust   NFSv4: Support NF...
1331
1332
  	if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
  		inode->i_blocks = fattr->du.nfs2.blocks;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1333
1334
1335
  
  	/* Update attrtimeo value if we're out of the unstable period */
  	if (invalid & NFS_INO_INVALID_ATTR) {
91d5b4702   Chuck Lever   NFS: add I/O perf...
1336
  		nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
  		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
3e7d950a5   Trond Myklebust   NFS: Fix a wrapar...
1338
  		nfsi->attrtimeo_timestamp = now;
4704f0e27   Trond Myklebust   NFS: Fix the reso...
1339
  		nfsi->attr_gencount = nfs_inc_attr_generation_counter();
6d2b29668   Trond Myklebust   NFS: Reset nfsi->...
1340
  	} else {
64672d55d   Peter Staubach   optimize attribut...
1341
  		if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
6d2b29668   Trond Myklebust   NFS: Reset nfsi->...
1342
1343
1344
1345
  			if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
  				nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
  			nfsi->attrtimeo_timestamp = now;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1346
  	}
f2115dc98   Trond Myklebust   NFS: Fix over-con...
1347
  	invalid &= ~NFS_INO_INVALID_ATTR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1348
1349
1350
1351
  	/* Don't invalidate the data if we were to blame */
  	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
  				|| S_ISLNK(inode->i_mode)))
  		invalid &= ~NFS_INO_INVALID_DATA;
412c77cee   Trond Myklebust   NFSv4: Defer inod...
1352
  	if (!nfs_have_delegation(inode, FMODE_READ) ||
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
1353
  			(save_cache_validity & NFS_INO_REVAL_FORCED))
552968098   Chuck Lever   [PATCH] NFS: spli...
1354
  		nfsi->cache_validity |= invalid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
1356
1357
1358
1359
1360
  
  	return 0;
   out_changed:
  	/*
  	 * Big trouble! The inode has become a different object.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1361
1362
  	printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o
  ",
3110ff804   Harvey Harrison   nfs: replace rema...
1363
  			__func__, inode->i_ino, inode->i_mode, fattr->mode);
b37b03b70   Trond Myklebust   NFS: Fix a spinlo...
1364
   out_err:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1365
1366
1367
1368
1369
1370
  	/*
  	 * No need to worry about unhashing the dentry, as the
  	 * lookup validation will know that the inode is bad.
  	 * (But we fall through to invalidate the caches.)
  	 */
  	nfs_invalidate_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371
  	return -ESTALE;
325cfed9a   Chuck Lever   NFS: make "inode ...
1372
1373
1374
1375
1376
1377
  
   out_fileid:
  	printk(KERN_ERR "NFS: server %s error: fileid changed
  "
  		"fsid %s: expected fileid 0x%Lx, got 0x%Lx
  ",
54ceac451   David Howells   NFS: Share NFS su...
1378
  		NFS_SERVER(inode)->nfs_client->cl_hostname, inode->i_sb->s_id,
325cfed9a   Chuck Lever   NFS: make "inode ...
1379
1380
  		(long long)nfsi->fileid, (long long)fattr->fileid);
  	goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1381
  }
55a975937   Trond Myklebust   NFS: Ensure the c...
1382

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383
  #ifdef CONFIG_NFS_V4
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1384
1385
1386
1387
1388
  /*
   * Clean out any remaining NFSv4 state that might be left over due
   * to open() calls that passed nfs_atomic_lookup, but failed to call
   * nfs_open().
   */
b57922d97   Al Viro   convert remaining...
1389
  void nfs4_evict_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1390
  {
b57922d97   Al Viro   convert remaining...
1391
1392
  	truncate_inode_pages(&inode->i_data, 0);
  	end_writeback(inode);
cbe826036   Benny Halevy   pnfs: layoutreturn
1393
1394
  	pnfs_return_layout(inode);
  	pnfs_destroy_layout(NFS_I(inode));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1395
  	/* If we are holding a delegation, return it! */
e6f810759   Trond Myklebust   NFS: Add an async...
1396
  	nfs_inode_return_delegation_noreclaim(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1397
1398
  	/* First call standard NFS clear_inode() code */
  	nfs_clear_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1399
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1400
  #endif
f7b422b17   David Howells   NFS: Split fs/nfs...
1401
  struct inode *nfs_alloc_inode(struct super_block *sb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1402
1403
  {
  	struct nfs_inode *nfsi;
e94b17660   Christoph Lameter   [PATCH] slab: rem...
1404
  	nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405
1406
  	if (!nfsi)
  		return NULL;
552968098   Chuck Lever   [PATCH] NFS: spli...
1407
1408
  	nfsi->flags = 0UL;
  	nfsi->cache_validity = 0UL;
458818ed7   Trond Myklebust   [PATCH] NFS: Fix ...
1409
1410
1411
1412
  #ifdef CONFIG_NFS_V3_ACL
  	nfsi->acl_access = ERR_PTR(-EAGAIN);
  	nfsi->acl_default = ERR_PTR(-EAGAIN);
  #endif
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
1413
1414
1415
  #ifdef CONFIG_NFS_V4
  	nfsi->nfs4_acl = NULL;
  #endif /* CONFIG_NFS_V4 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1416
1417
  	return &nfsi->vfs_inode;
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
1418
  static void nfs_i_callback(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1419
  {
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
1420
  	struct inode *inode = container_of(head, struct inode, i_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1421
1422
  	kmem_cache_free(nfs_inode_cachep, NFS_I(inode));
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
1423
1424
1425
1426
  void nfs_destroy_inode(struct inode *inode)
  {
  	call_rcu(&inode->i_rcu, nfs_i_callback);
  }
d75d54147   Andrew Morton   git-nfs-build-fixes
1427
1428
1429
1430
1431
1432
1433
  static inline void nfs4_init_once(struct nfs_inode *nfsi)
  {
  #ifdef CONFIG_NFS_V4
  	INIT_LIST_HEAD(&nfsi->open_states);
  	nfsi->delegation = NULL;
  	nfsi->delegation_state = 0;
  	init_rwsem(&nfsi->rwsem);
e5e940170   Benny Halevy   NFS: create and d...
1434
  	nfsi->layout = NULL;
e0c2b3801   Fred Isaman   NFSv4.1: filelayo...
1435
  	atomic_set(&nfsi->commits_outstanding, 0);
d75d54147   Andrew Morton   git-nfs-build-fixes
1436
1437
  #endif
  }
f7b422b17   David Howells   NFS: Split fs/nfs...
1438

51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
1439
  static void init_once(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1440
1441
  {
  	struct nfs_inode *nfsi = (struct nfs_inode *) foo;
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
1442
  	inode_init_once(&nfsi->vfs_inode);
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
1443
1444
1445
1446
  	INIT_LIST_HEAD(&nfsi->open_files);
  	INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
  	INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
  	INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
1447
  	nfsi->npages = 0;
ff778d02b   Trond Myklebust   NFS: Add a count ...
1448
  	nfsi->ncommit = 0;
565277f63   Trond Myklebust   NFS: Fix a race i...
1449
1450
1451
  	atomic_set(&nfsi->silly_count, 1);
  	INIT_HLIST_HEAD(&nfsi->silly_list);
  	init_waitqueue_head(&nfsi->waitqueue);
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
1452
  	nfs4_init_once(nfsi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1453
  }
20c2df83d   Paul Mundt   mm: Remove slab d...
1454

f7b422b17   David Howells   NFS: Split fs/nfs...
1455
  static int __init nfs_init_inodecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
1457
1458
  {
  	nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
  					     sizeof(struct nfs_inode),
fffb60f93   Paul Jackson   [PATCH] cpuset me...
1459
1460
  					     0, (SLAB_RECLAIM_ACCOUNT|
  						SLAB_MEM_SPREAD),
20c2df83d   Paul Mundt   mm: Remove slab d...
1461
  					     init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1462
1463
1464
1465
1466
  	if (nfs_inode_cachep == NULL)
  		return -ENOMEM;
  
  	return 0;
  }
266bee886   David Brownell   [PATCH] fix stati...
1467
  static void nfs_destroy_inodecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1468
  {
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
1469
  	kmem_cache_destroy(nfs_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1470
  }
5746006f1   Trond Myklebust   NFS: Add an nfsio...
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
  struct workqueue_struct *nfsiod_workqueue;
  
  /*
   * start up the nfsiod workqueue
   */
  static int nfsiod_start(void)
  {
  	struct workqueue_struct *wq;
  	dprintk("RPC:       creating workqueue nfsiod
  ");
ada609ee2   Tejun Heo   workqueue: use WQ...
1481
  	wq = alloc_workqueue("nfsiod", WQ_MEM_RECLAIM, 0);
5746006f1   Trond Myklebust   NFS: Add an nfsio...
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
  	if (wq == NULL)
  		return -ENOMEM;
  	nfsiod_workqueue = wq;
  	return 0;
  }
  
  /*
   * Destroy the nfsiod workqueue
   */
  static void nfsiod_stop(void)
  {
  	struct workqueue_struct *wq;
  
  	wq = nfsiod_workqueue;
  	if (wq == NULL)
  		return;
  	nfsiod_workqueue = NULL;
  	destroy_workqueue(wq);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
1502
1503
1504
1505
1506
  /*
   * Initialize NFS
   */
  static int __init init_nfs_fs(void)
  {
  	int err;
955a857e0   Bryan Schumaker   NFS: new idmapper
1507
1508
1509
  	err = nfs_idmap_init();
  	if (err < 0)
  		goto out9;
e571cbf1a   Trond Myklebust   NFS: Add a dns re...
1510
1511
1512
  	err = nfs_dns_resolver_init();
  	if (err < 0)
  		goto out8;
8ec442ae4   David Howells   NFS: Register NFS...
1513
1514
1515
  	err = nfs_fscache_register();
  	if (err < 0)
  		goto out7;
5746006f1   Trond Myklebust   NFS: Add an nfsio...
1516
1517
1518
  	err = nfsiod_start();
  	if (err)
  		goto out6;
6aaca5665   David Howells   NFS: Add server a...
1519
1520
1521
  	err = nfs_fs_proc_init();
  	if (err)
  		goto out5;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
  	err = nfs_init_nfspagecache();
  	if (err)
  		goto out4;
  
  	err = nfs_init_inodecache();
  	if (err)
  		goto out3;
  
  	err = nfs_init_readpagecache();
  	if (err)
  		goto out2;
  
  	err = nfs_init_writepagecache();
  	if (err)
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1537
1538
1539
  	err = nfs_init_directcache();
  	if (err)
  		goto out0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1540
1541
1542
1543
  
  #ifdef CONFIG_PROC_FS
  	rpc_proc_register(&nfs_rpcstat);
  #endif
f7b422b17   David Howells   NFS: Split fs/nfs...
1544
  	if ((err = register_nfs_fs()) != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1545
1546
1547
1548
1549
1550
  		goto out;
  	return 0;
  out:
  #ifdef CONFIG_PROC_FS
  	rpc_proc_unregister("nfs");
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1551
  	nfs_destroy_directcache();
6b59a7546   Chuck Lever   NFS: Fix error re...
1552
  out0:
6b59a7546   Chuck Lever   NFS: Fix error re...
1553
  	nfs_destroy_writepagecache();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1554
1555
1556
1557
1558
1559
1560
  out1:
  	nfs_destroy_readpagecache();
  out2:
  	nfs_destroy_inodecache();
  out3:
  	nfs_destroy_nfspagecache();
  out4:
6aaca5665   David Howells   NFS: Add server a...
1561
1562
  	nfs_fs_proc_exit();
  out5:
5746006f1   Trond Myklebust   NFS: Add an nfsio...
1563
1564
  	nfsiod_stop();
  out6:
8ec442ae4   David Howells   NFS: Register NFS...
1565
1566
  	nfs_fscache_unregister();
  out7:
e571cbf1a   Trond Myklebust   NFS: Add a dns re...
1567
1568
  	nfs_dns_resolver_destroy();
  out8:
955a857e0   Bryan Schumaker   NFS: new idmapper
1569
1570
  	nfs_idmap_quit();
  out9:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571
1572
1573
1574
1575
  	return err;
  }
  
  static void __exit exit_nfs_fs(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1576
  	nfs_destroy_directcache();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1577
1578
1579
1580
  	nfs_destroy_writepagecache();
  	nfs_destroy_readpagecache();
  	nfs_destroy_inodecache();
  	nfs_destroy_nfspagecache();
8ec442ae4   David Howells   NFS: Register NFS...
1581
  	nfs_fscache_unregister();
e571cbf1a   Trond Myklebust   NFS: Add a dns re...
1582
  	nfs_dns_resolver_destroy();
955a857e0   Bryan Schumaker   NFS: new idmapper
1583
  	nfs_idmap_quit();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1584
1585
1586
  #ifdef CONFIG_PROC_FS
  	rpc_proc_unregister("nfs");
  #endif
f4eecd5da   Andy Adamson   NFS implement v4....
1587
  	nfs_cleanup_cb_ident_idr();
f7b422b17   David Howells   NFS: Split fs/nfs...
1588
  	unregister_nfs_fs();
6aaca5665   David Howells   NFS: Add server a...
1589
  	nfs_fs_proc_exit();
5746006f1   Trond Myklebust   NFS: Add an nfsio...
1590
  	nfsiod_stop();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1591
1592
1593
1594
1595
  }
  
  /* Not quite true; I just maintain it */
  MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
  MODULE_LICENSE("GPL");
f43bf0beb   Trond Myklebust   NFS: Add a boot p...
1596
  module_param(enable_ino64, bool, 0644);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
1598
1599
  
  module_init(init_nfs_fs)
  module_exit(exit_nfs_fs)