xref: /openbmc/linux/fs/nfs/inode.c (revision 24f68eb5bf14a74027946970a18bc902e19d986a)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  linux/fs/nfs/inode.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 1992  Rick Sladkey
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *  nfs inode and superblock handling functions
81da177e4SLinus Torvalds  *
9526719baSAlan Cox  *  Modularised by Alan Cox <alan@lxorguk.ukuu.org.uk>, while hacking some
101da177e4SLinus Torvalds  *  experimental NFS changes. Modularisation taken straight from SYS5 fs.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  *  Change to nfs_read_super() to permit NFS mounts to multi-homed hosts.
131da177e4SLinus Torvalds  *  J.S.Peatfield@damtp.cam.ac.uk
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  */
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds #include <linux/module.h>
181da177e4SLinus Torvalds #include <linux/init.h>
19174cd4b1SIngo Molnar #include <linux/sched/signal.h>
201da177e4SLinus Torvalds #include <linux/time.h>
211da177e4SLinus Torvalds #include <linux/kernel.h>
221da177e4SLinus Torvalds #include <linux/mm.h>
231da177e4SLinus Torvalds #include <linux/string.h>
241da177e4SLinus Torvalds #include <linux/stat.h>
251da177e4SLinus Torvalds #include <linux/errno.h>
261da177e4SLinus Torvalds #include <linux/unistd.h>
271da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
281da177e4SLinus Torvalds #include <linux/sunrpc/stats.h>
294ece3a2dSChuck Lever #include <linux/sunrpc/metrics.h>
301da177e4SLinus Torvalds #include <linux/nfs_fs.h>
311da177e4SLinus Torvalds #include <linux/nfs_mount.h>
321da177e4SLinus Torvalds #include <linux/nfs4_mount.h>
331da177e4SLinus Torvalds #include <linux/lockd/bind.h>
341da177e4SLinus Torvalds #include <linux/seq_file.h>
351da177e4SLinus Torvalds #include <linux/mount.h>
361da177e4SLinus Torvalds #include <linux/vfs.h>
379cdb3883SManoj Naik #include <linux/inet.h>
389cdb3883SManoj Naik #include <linux/nfs_xdr.h>
395a0e3ad6STejun Heo #include <linux/slab.h>
403fa0b4e2SFrank Filz #include <linux/compat.h>
41d310310cSJeff Layton #include <linux/freezer.h>
427c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
431eb5d98fSJeff Layton #include <linux/iversion.h>
441da177e4SLinus Torvalds 
454ce79717STrond Myklebust #include "nfs4_fs.h"
46a72b4422STrond Myklebust #include "callback.h"
471da177e4SLinus Torvalds #include "delegation.h"
48d9ef5a8cSChuck Lever #include "iostat.h"
49f7b422b1SDavid Howells #include "internal.h"
508ec442aeSDavid Howells #include "fscache.h"
51e5e94017SBenny Halevy #include "pnfs.h"
52ab7017a3SBryan Schumaker #include "nfs.h"
531b340d01SStanislav Kinsbursky #include "netns.h"
54996bc4f4STrond Myklebust #include "sysfs.h"
551da177e4SLinus Torvalds 
56f4ce1299STrond Myklebust #include "nfstrace.h"
57f4ce1299STrond Myklebust 
581da177e4SLinus Torvalds #define NFSDBG_FACILITY		NFSDBG_VFS
591da177e4SLinus Torvalds 
60f43bf0beSTrond Myklebust #define NFS_64_BIT_INODE_NUMBERS_ENABLED	1
61f43bf0beSTrond Myklebust 
62f43bf0beSTrond Myklebust /* Default is to see 64-bit inode numbers */
6390ab5ee9SRusty Russell static bool enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED;
64f43bf0beSTrond Myklebust 
6524aa1fe6STrond Myklebust static int nfs_update_inode(struct inode *, struct nfs_fattr *);
661da177e4SLinus Torvalds 
67e18b890bSChristoph Lameter static struct kmem_cache * nfs_inode_cachep;
68b7fa0554SAndreas Gruenbacher 
691da177e4SLinus Torvalds static inline unsigned long
nfs_fattr_to_ino_t(struct nfs_fattr * fattr)701da177e4SLinus Torvalds nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
711da177e4SLinus Torvalds {
721da177e4SLinus Torvalds 	return nfs_fileid_to_ino_t(fattr->fileid);
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds 
nfs_wait_bit_killable(struct wait_bit_key * key,int mode)75f5d39b02SPeter Zijlstra int nfs_wait_bit_killable(struct wait_bit_key *key, int mode)
7672cb77f4STrond Myklebust {
77f5d39b02SPeter Zijlstra 	schedule();
78dfd01f02SPeter Zijlstra 	if (signal_pending_state(mode, current))
79dfd01f02SPeter Zijlstra 		return -ERESTARTSYS;
8072cb77f4STrond Myklebust 	return 0;
8172cb77f4STrond Myklebust }
8289d77c8fSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_wait_bit_killable);
8372cb77f4STrond Myklebust 
8472cb77f4STrond Myklebust /**
85f43bf0beSTrond Myklebust  * nfs_compat_user_ino64 - returns the user-visible inode number
86f43bf0beSTrond Myklebust  * @fileid: 64-bit fileid
87f43bf0beSTrond Myklebust  *
88f43bf0beSTrond Myklebust  * This function returns a 32-bit inode number if the boot parameter
89f43bf0beSTrond Myklebust  * nfs.enable_ino64 is zero.
90f43bf0beSTrond Myklebust  */
nfs_compat_user_ino64(u64 fileid)91f43bf0beSTrond Myklebust u64 nfs_compat_user_ino64(u64 fileid)
92f43bf0beSTrond Myklebust {
933fa0b4e2SFrank Filz #ifdef CONFIG_COMPAT
943fa0b4e2SFrank Filz 	compat_ulong_t ino;
953fa0b4e2SFrank Filz #else
963fa0b4e2SFrank Filz 	unsigned long ino;
973fa0b4e2SFrank Filz #endif
98f43bf0beSTrond Myklebust 
99f43bf0beSTrond Myklebust 	if (enable_ino64)
100f43bf0beSTrond Myklebust 		return fileid;
101f43bf0beSTrond Myklebust 	ino = fileid;
102f43bf0beSTrond Myklebust 	if (sizeof(ino) < sizeof(fileid))
103f43bf0beSTrond Myklebust 		ino ^= fileid >> (sizeof(fileid)-sizeof(ino)) * 8;
104f43bf0beSTrond Myklebust 	return ino;
105f43bf0beSTrond Myklebust }
106f43bf0beSTrond Myklebust 
nfs_drop_inode(struct inode * inode)107eed99357STrond Myklebust int nfs_drop_inode(struct inode *inode)
108eed99357STrond Myklebust {
109eed99357STrond Myklebust 	return NFS_STALE(inode) || generic_drop_inode(inode);
110eed99357STrond Myklebust }
111eed99357STrond Myklebust EXPORT_SYMBOL_GPL(nfs_drop_inode);
112eed99357STrond Myklebust 
nfs_clear_inode(struct inode * inode)11319d87ca3SBryan Schumaker void nfs_clear_inode(struct inode *inode)
1141da177e4SLinus Torvalds {
115da6d503aSTrond Myklebust 	/*
116da6d503aSTrond Myklebust 	 * The following should never happen...
117da6d503aSTrond Myklebust 	 */
118f48407ddSTrond Myklebust 	WARN_ON_ONCE(nfs_have_writebacks(inode));
119f48407ddSTrond Myklebust 	WARN_ON_ONCE(!list_empty(&NFS_I(inode)->open_files));
120ada70d94STrond Myklebust 	nfs_zap_acl_cache(inode);
1211c3c07e9STrond Myklebust 	nfs_access_zap_cache(inode);
122f1fe29b4SDavid Howells 	nfs_fscache_clear_inode(inode);
1231da177e4SLinus Torvalds }
12489d77c8fSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_clear_inode);
1251da177e4SLinus Torvalds 
nfs_evict_inode(struct inode * inode)126b57922d9SAl Viro void nfs_evict_inode(struct inode *inode)
127b57922d9SAl Viro {
12891b0abe3SJohannes Weiner 	truncate_inode_pages_final(&inode->i_data);
129dbd5768fSJan Kara 	clear_inode(inode);
130b57922d9SAl Viro 	nfs_clear_inode(inode);
131b57922d9SAl Viro }
132b57922d9SAl Viro 
nfs_sync_inode(struct inode * inode)1339e1681c2STrond Myklebust int nfs_sync_inode(struct inode *inode)
1344d346beaSTrond Myklebust {
13595d9f6c3SChristoph Hellwig 	inode_dio_wait(inode);
1364d346beaSTrond Myklebust 	return nfs_wb_all(inode);
1374d346beaSTrond Myklebust }
1389e1681c2STrond Myklebust EXPORT_SYMBOL_GPL(nfs_sync_inode);
1394d346beaSTrond Myklebust 
14029884df0STrond Myklebust /**
14129884df0STrond Myklebust  * nfs_sync_mapping - helper to flush all mmapped dirty data to disk
142302fad7bSTrond Myklebust  * @mapping: pointer to struct address_space
14329884df0STrond Myklebust  */
nfs_sync_mapping(struct address_space * mapping)14429884df0STrond Myklebust int nfs_sync_mapping(struct address_space *mapping)
14529884df0STrond Myklebust {
1465cf95214STrond Myklebust 	int ret = 0;
14729884df0STrond Myklebust 
1485cf95214STrond Myklebust 	if (mapping->nrpages != 0) {
14929884df0STrond Myklebust 		unmap_mapping_range(mapping, 0, 0, 0);
15029884df0STrond Myklebust 		ret = nfs_wb_all(mapping->host);
1515cf95214STrond Myklebust 	}
15229884df0STrond Myklebust 	return ret;
15329884df0STrond Myklebust }
15429884df0STrond Myklebust 
nfs_attribute_timeout(struct inode * inode)155187e593dSTrond Myklebust static int nfs_attribute_timeout(struct inode *inode)
156187e593dSTrond Myklebust {
157187e593dSTrond Myklebust 	struct nfs_inode *nfsi = NFS_I(inode);
158187e593dSTrond Myklebust 
159187e593dSTrond Myklebust 	return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo);
160187e593dSTrond Myklebust }
161187e593dSTrond Myklebust 
nfs_check_cache_flags_invalid(struct inode * inode,unsigned long flags)16213c0b082STrond Myklebust static bool nfs_check_cache_flags_invalid(struct inode *inode,
16313c0b082STrond Myklebust 					  unsigned long flags)
16461540bf6STrond Myklebust {
16561540bf6STrond Myklebust 	unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
16661540bf6STrond Myklebust 
16761540bf6STrond Myklebust 	return (cache_validity & flags) != 0;
16861540bf6STrond Myklebust }
16961540bf6STrond Myklebust 
nfs_check_cache_invalid(struct inode * inode,unsigned long flags)17061540bf6STrond Myklebust bool nfs_check_cache_invalid(struct inode *inode, unsigned long flags)
17161540bf6STrond Myklebust {
17213c0b082STrond Myklebust 	if (nfs_check_cache_flags_invalid(inode, flags))
17313c0b082STrond Myklebust 		return true;
17413c0b082STrond Myklebust 	return nfs_attribute_cache_expired(inode);
17561540bf6STrond Myklebust }
17695ad37f9SFrank van der Linden EXPORT_SYMBOL_GPL(nfs_check_cache_invalid);
17761540bf6STrond Myklebust 
178848fdd62STrond Myklebust #ifdef CONFIG_NFS_V4_2
nfs_has_xattr_cache(const struct nfs_inode * nfsi)179848fdd62STrond Myklebust static bool nfs_has_xattr_cache(const struct nfs_inode *nfsi)
180848fdd62STrond Myklebust {
181848fdd62STrond Myklebust 	return nfsi->xattr_cache != NULL;
182848fdd62STrond Myklebust }
183848fdd62STrond Myklebust #else
nfs_has_xattr_cache(const struct nfs_inode * nfsi)184848fdd62STrond Myklebust static bool nfs_has_xattr_cache(const struct nfs_inode *nfsi)
185848fdd62STrond Myklebust {
186848fdd62STrond Myklebust 	return false;
187848fdd62STrond Myklebust }
188848fdd62STrond Myklebust #endif
189848fdd62STrond Myklebust 
nfs_set_cache_invalid(struct inode * inode,unsigned long flags)190fd6d3feeSTrond Myklebust void nfs_set_cache_invalid(struct inode *inode, unsigned long flags)
1916edf9609STrond Myklebust {
1926edf9609STrond Myklebust 	struct nfs_inode *nfsi = NFS_I(inode);
1933f0b3cf4STrond Myklebust 	bool have_delegation = NFS_PROTO(inode)->have_delegation(inode, FMODE_READ);
1946edf9609STrond Myklebust 
1953f0b3cf4STrond Myklebust 	if (have_delegation) {
1963f0b3cf4STrond Myklebust 		if (!(flags & NFS_INO_REVAL_FORCED))
197720869ebSTrond Myklebust 			flags &= ~(NFS_INO_INVALID_MODE |
198cc7f2daeSTrond Myklebust 				   NFS_INO_INVALID_OTHER |
199cc7f2daeSTrond Myklebust 				   NFS_INO_INVALID_XATTR);
200cc7f2daeSTrond Myklebust 		flags &= ~(NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE);
20141e97b7fSTrond Myklebust 	}
2023f0b3cf4STrond Myklebust 
203848fdd62STrond Myklebust 	if (!nfs_has_xattr_cache(nfsi))
204848fdd62STrond Myklebust 		flags &= ~NFS_INO_INVALID_XATTR;
2056edf9609STrond Myklebust 	if (flags & NFS_INO_INVALID_DATA)
206a6b5a28eSDave Wysochanski 		nfs_fscache_invalidate(inode, 0);
20741e97b7fSTrond Myklebust 	flags &= ~NFS_INO_REVAL_FORCED;
208488796ecSTrond Myklebust 
2096173b0bfSMike Snitzer 	flags |= nfsi->cache_validity;
2106173b0bfSMike Snitzer 	if (inode->i_mapping->nrpages == 0)
2116173b0bfSMike Snitzer 		flags &= ~NFS_INO_INVALID_DATA;
212488796ecSTrond Myklebust 
2136173b0bfSMike Snitzer 	/* pairs with nfs_clear_invalid_mapping()'s smp_load_acquire() */
2146173b0bfSMike Snitzer 	smp_store_release(&nfsi->cache_validity, flags);
2156173b0bfSMike Snitzer 
2166173b0bfSMike Snitzer 	if (inode->i_mapping->nrpages == 0 ||
2176173b0bfSMike Snitzer 	    nfsi->cache_validity & NFS_INO_INVALID_DATA) {
2183db63daaSNeilBrown 		nfs_ooo_clear(nfsi);
2193db63daaSNeilBrown 	}
22093c2e5e0SBenjamin Coddington 	trace_nfs_set_cache_invalid(inode, 0);
2216edf9609STrond Myklebust }
222b6f80a2eSTrond Myklebust EXPORT_SYMBOL_GPL(nfs_set_cache_invalid);
2236edf9609STrond Myklebust 
2241da177e4SLinus Torvalds /*
2251da177e4SLinus Torvalds  * Invalidate the local caches
2261da177e4SLinus Torvalds  */
nfs_zap_caches_locked(struct inode * inode)227b37b03b7STrond Myklebust static void nfs_zap_caches_locked(struct inode *inode)
2281da177e4SLinus Torvalds {
2291da177e4SLinus Torvalds 	struct nfs_inode *nfsi = NFS_I(inode);
2301da177e4SLinus Torvalds 	int mode = inode->i_mode;
2311da177e4SLinus Torvalds 
23291d5b470SChuck Lever 	nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
23391d5b470SChuck Lever 
234c7c20973STrond Myklebust 	nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
235c7c20973STrond Myklebust 	nfsi->attrtimeo_timestamp = jiffies;
2361da177e4SLinus Torvalds 
23788a6099fSTrond Myklebust 	if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
23888a6099fSTrond Myklebust 		nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR |
23988a6099fSTrond Myklebust 						     NFS_INO_INVALID_DATA |
24088a6099fSTrond Myklebust 						     NFS_INO_INVALID_ACCESS |
24188a6099fSTrond Myklebust 						     NFS_INO_INVALID_ACL |
24288a6099fSTrond Myklebust 						     NFS_INO_INVALID_XATTR);
24388a6099fSTrond Myklebust 	else
24488a6099fSTrond Myklebust 		nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR |
24588a6099fSTrond Myklebust 						     NFS_INO_INVALID_ACCESS |
24688a6099fSTrond Myklebust 						     NFS_INO_INVALID_ACL |
24788a6099fSTrond Myklebust 						     NFS_INO_INVALID_XATTR);
248fd1defc2STrond Myklebust 	nfs_zap_label_cache_locked(nfsi);
249de242c0bSDavid Howells }
250dc59250cSChuck Lever 
nfs_zap_caches(struct inode * inode)251b37b03b7STrond Myklebust void nfs_zap_caches(struct inode *inode)
252b37b03b7STrond Myklebust {
253b37b03b7STrond Myklebust 	spin_lock(&inode->i_lock);
254b37b03b7STrond Myklebust 	nfs_zap_caches_locked(inode);
255dc59250cSChuck Lever 	spin_unlock(&inode->i_lock);
256ada70d94STrond Myklebust }
257ada70d94STrond Myklebust 
nfs_zap_mapping(struct inode * inode,struct address_space * mapping)258cd9ae2b6STrond Myklebust void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
259cd9ae2b6STrond Myklebust {
260cd9ae2b6STrond Myklebust 	if (mapping->nrpages != 0) {
261cd9ae2b6STrond Myklebust 		spin_lock(&inode->i_lock);
2626edf9609STrond Myklebust 		nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA);
263cd9ae2b6STrond Myklebust 		spin_unlock(&inode->i_lock);
264cd9ae2b6STrond Myklebust 	}
265cd9ae2b6STrond Myklebust }
266cd9ae2b6STrond Myklebust 
nfs_zap_acl_cache(struct inode * inode)267f41f7418STrond Myklebust void nfs_zap_acl_cache(struct inode *inode)
268ada70d94STrond Myklebust {
269ada70d94STrond Myklebust 	void (*clear_acl_cache)(struct inode *);
270ada70d94STrond Myklebust 
271ada70d94STrond Myklebust 	clear_acl_cache = NFS_PROTO(inode)->clear_acl_cache;
272ada70d94STrond Myklebust 	if (clear_acl_cache != NULL)
273ada70d94STrond Myklebust 		clear_acl_cache(inode);
274dc59250cSChuck Lever 	spin_lock(&inode->i_lock);
27555296809SChuck Lever 	NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_ACL;
276dc59250cSChuck Lever 	spin_unlock(&inode->i_lock);
2771da177e4SLinus Torvalds }
2781c606fb7SBryan Schumaker EXPORT_SYMBOL_GPL(nfs_zap_acl_cache);
2791da177e4SLinus Torvalds 
nfs_invalidate_atime(struct inode * inode)280c4812998STrond Myklebust void nfs_invalidate_atime(struct inode *inode)
281c4812998STrond Myklebust {
282c4812998STrond Myklebust 	spin_lock(&inode->i_lock);
2836edf9609STrond Myklebust 	nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME);
284c4812998STrond Myklebust 	spin_unlock(&inode->i_lock);
285c4812998STrond Myklebust }
286ddda8e0aSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_invalidate_atime);
287c4812998STrond Myklebust 
2881da177e4SLinus Torvalds /*
289b37b03b7STrond Myklebust  * Invalidate, but do not unhash, the inode.
290b37b03b7STrond Myklebust  * NB: must be called with inode->i_lock held!
2911da177e4SLinus Torvalds  */
nfs_set_inode_stale_locked(struct inode * inode)29293ce4af7STrond Myklebust static void nfs_set_inode_stale_locked(struct inode *inode)
2931da177e4SLinus Torvalds {
2943a10c30aSBenny Halevy 	set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
295b37b03b7STrond Myklebust 	nfs_zap_caches_locked(inode);
29693ce4af7STrond Myklebust 	trace_nfs_set_inode_stale(inode);
29793ce4af7STrond Myklebust }
29893ce4af7STrond Myklebust 
nfs_set_inode_stale(struct inode * inode)29993ce4af7STrond Myklebust void nfs_set_inode_stale(struct inode *inode)
30093ce4af7STrond Myklebust {
30193ce4af7STrond Myklebust 	spin_lock(&inode->i_lock);
30293ce4af7STrond Myklebust 	nfs_set_inode_stale_locked(inode);
30393ce4af7STrond Myklebust 	spin_unlock(&inode->i_lock);
3041da177e4SLinus Torvalds }
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds struct nfs_find_desc {
3071da177e4SLinus Torvalds 	struct nfs_fh		*fh;
3081da177e4SLinus Torvalds 	struct nfs_fattr	*fattr;
3091da177e4SLinus Torvalds };
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds /*
3121da177e4SLinus Torvalds  * In NFSv3 we can have 64bit inode numbers. In order to support
3131da177e4SLinus Torvalds  * this, and re-exported directories (also seen in NFSv2)
3141da177e4SLinus Torvalds  * we are forced to allow 2 different inodes to have the same
3151da177e4SLinus Torvalds  * i_ino.
3161da177e4SLinus Torvalds  */
3171da177e4SLinus Torvalds static int
nfs_find_actor(struct inode * inode,void * opaque)3181da177e4SLinus Torvalds nfs_find_actor(struct inode *inode, void *opaque)
3191da177e4SLinus Torvalds {
3207e7ce2ccSyuzhe 	struct nfs_find_desc	*desc = opaque;
3211da177e4SLinus Torvalds 	struct nfs_fh		*fh = desc->fh;
3221da177e4SLinus Torvalds 	struct nfs_fattr	*fattr = desc->fattr;
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds 	if (NFS_FILEID(inode) != fattr->fileid)
3251da177e4SLinus Torvalds 		return 0;
3266e3e2c43SAl Viro 	if (inode_wrong_type(inode, fattr->mode))
327f6488c9bSJeff Layton 		return 0;
3281da177e4SLinus Torvalds 	if (nfs_compare_fh(NFS_FH(inode), fh))
3291da177e4SLinus Torvalds 		return 0;
3301da177e4SLinus Torvalds 	if (is_bad_inode(inode) || NFS_STALE(inode))
3311da177e4SLinus Torvalds 		return 0;
3321da177e4SLinus Torvalds 	return 1;
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds static int
nfs_init_locked(struct inode * inode,void * opaque)3361da177e4SLinus Torvalds nfs_init_locked(struct inode *inode, void *opaque)
3371da177e4SLinus Torvalds {
3387e7ce2ccSyuzhe 	struct nfs_find_desc	*desc = opaque;
3391da177e4SLinus Torvalds 	struct nfs_fattr	*fattr = desc->fattr;
3401da177e4SLinus Torvalds 
34199fadcd7SBenny Halevy 	set_nfs_fileid(inode, fattr->fileid);
342916ec34dSTrond Myklebust 	inode->i_mode = fattr->mode;
3431da177e4SLinus Torvalds 	nfs_copy_fh(NFS_FH(inode), desc->fh);
3441da177e4SLinus Torvalds 	return 0;
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds 
347e058f70bSSteve Dickson #ifdef CONFIG_NFS_V4_SECURITY_LABEL
nfs_clear_label_invalid(struct inode * inode)348fd1defc2STrond Myklebust static void nfs_clear_label_invalid(struct inode *inode)
349fd1defc2STrond Myklebust {
350fd1defc2STrond Myklebust 	spin_lock(&inode->i_lock);
351fd1defc2STrond Myklebust 	NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_LABEL;
352fd1defc2STrond Myklebust 	spin_unlock(&inode->i_lock);
353fd1defc2STrond Myklebust }
354fd1defc2STrond Myklebust 
nfs_setsecurity(struct inode * inode,struct nfs_fattr * fattr)355dd225cb3SAnna Schumaker void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr)
356aa9c2669SDavid Quigley {
357aa9c2669SDavid Quigley 	int error;
358aa9c2669SDavid Quigley 
359dd225cb3SAnna Schumaker 	if (fattr->label == NULL)
360aa9c2669SDavid Quigley 		return;
361aa9c2669SDavid Quigley 
362aa9c2669SDavid Quigley 	if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL) && inode->i_security) {
363dd225cb3SAnna Schumaker 		error = security_inode_notifysecctx(inode, fattr->label->label,
364dd225cb3SAnna Schumaker 				fattr->label->len);
365aa9c2669SDavid Quigley 		if (error)
366aa9c2669SDavid Quigley 			printk(KERN_ERR "%s() %s %d "
367aa9c2669SDavid Quigley 					"security_inode_notifysecctx() %d\n",
368aa9c2669SDavid Quigley 					__func__,
369dd225cb3SAnna Schumaker 					(char *)fattr->label->label,
370dd225cb3SAnna Schumaker 					fattr->label->len, error);
371fd1defc2STrond Myklebust 		nfs_clear_label_invalid(inode);
372aa9c2669SDavid Quigley 	}
373aa9c2669SDavid Quigley }
374aa9c2669SDavid Quigley 
nfs4_label_alloc(struct nfs_server * server,gfp_t flags)375e058f70bSSteve Dickson struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
376e058f70bSSteve Dickson {
377e48c81bbSTrond Myklebust 	struct nfs4_label *label;
378e058f70bSSteve Dickson 
379e058f70bSSteve Dickson 	if (!(server->caps & NFS_CAP_SECURITY_LABEL))
380e48c81bbSTrond Myklebust 		return NULL;
381e058f70bSSteve Dickson 
382e058f70bSSteve Dickson 	label = kzalloc(sizeof(struct nfs4_label), flags);
383e058f70bSSteve Dickson 	if (label == NULL)
384e058f70bSSteve Dickson 		return ERR_PTR(-ENOMEM);
385e058f70bSSteve Dickson 
386e058f70bSSteve Dickson 	label->label = kzalloc(NFS4_MAXLABELLEN, flags);
387e058f70bSSteve Dickson 	if (label->label == NULL) {
388e058f70bSSteve Dickson 		kfree(label);
389e058f70bSSteve Dickson 		return ERR_PTR(-ENOMEM);
390e058f70bSSteve Dickson 	}
391e058f70bSSteve Dickson 	label->len = NFS4_MAXLABELLEN;
392e058f70bSSteve Dickson 
393e058f70bSSteve Dickson 	return label;
394e058f70bSSteve Dickson }
395e058f70bSSteve Dickson EXPORT_SYMBOL_GPL(nfs4_label_alloc);
396aa9c2669SDavid Quigley #else
nfs_setsecurity(struct inode * inode,struct nfs_fattr * fattr)397dd225cb3SAnna Schumaker void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr)
398aa9c2669SDavid Quigley {
399aa9c2669SDavid Quigley }
400e058f70bSSteve Dickson #endif
401aa9c2669SDavid Quigley EXPORT_SYMBOL_GPL(nfs_setsecurity);
402e058f70bSSteve Dickson 
403f174ff7aSPeng Tao /* Search for inode identified by fh, fileid and i_mode in inode cache. */
404f174ff7aSPeng Tao struct inode *
nfs_ilookup(struct super_block * sb,struct nfs_fattr * fattr,struct nfs_fh * fh)405f174ff7aSPeng Tao nfs_ilookup(struct super_block *sb, struct nfs_fattr *fattr, struct nfs_fh *fh)
406f174ff7aSPeng Tao {
407f174ff7aSPeng Tao 	struct nfs_find_desc desc = {
408f174ff7aSPeng Tao 		.fh	= fh,
409f174ff7aSPeng Tao 		.fattr	= fattr,
410f174ff7aSPeng Tao 	};
411f174ff7aSPeng Tao 	struct inode *inode;
412f174ff7aSPeng Tao 	unsigned long hash;
413f174ff7aSPeng Tao 
414f174ff7aSPeng Tao 	if (!(fattr->valid & NFS_ATTR_FATTR_FILEID) ||
415f174ff7aSPeng Tao 	    !(fattr->valid & NFS_ATTR_FATTR_TYPE))
416f174ff7aSPeng Tao 		return NULL;
417f174ff7aSPeng Tao 
418f174ff7aSPeng Tao 	hash = nfs_fattr_to_ino_t(fattr);
419f174ff7aSPeng Tao 	inode = ilookup5(sb, hash, nfs_find_actor, &desc);
420f174ff7aSPeng Tao 
421f174ff7aSPeng Tao 	dprintk("%s: returning %p\n", __func__, inode);
422f174ff7aSPeng Tao 	return inode;
423f174ff7aSPeng Tao }
424f174ff7aSPeng Tao 
nfs_inode_init_regular(struct nfs_inode * nfsi)425e591b298STrond Myklebust static void nfs_inode_init_regular(struct nfs_inode *nfsi)
426e591b298STrond Myklebust {
427e591b298STrond Myklebust 	atomic_long_set(&nfsi->nrequests, 0);
42867f4b5dcSTrond Myklebust 	atomic_long_set(&nfsi->redirtied_pages, 0);
429e591b298STrond Myklebust 	INIT_LIST_HEAD(&nfsi->commit_info.list);
430e591b298STrond Myklebust 	atomic_long_set(&nfsi->commit_info.ncommit, 0);
431e591b298STrond Myklebust 	atomic_set(&nfsi->commit_info.rpcs_out, 0);
432e591b298STrond Myklebust 	mutex_init(&nfsi->commit_mutex);
433e591b298STrond Myklebust }
434e591b298STrond Myklebust 
nfs_inode_init_dir(struct nfs_inode * nfsi)435e591b298STrond Myklebust static void nfs_inode_init_dir(struct nfs_inode *nfsi)
436e591b298STrond Myklebust {
437e591b298STrond Myklebust 	nfsi->cache_change_attribute = 0;
438e591b298STrond Myklebust 	memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
439e591b298STrond Myklebust 	init_rwsem(&nfsi->rmdir_sem);
440e591b298STrond Myklebust }
441e591b298STrond Myklebust 
4421da177e4SLinus Torvalds /*
4431da177e4SLinus Torvalds  * This is our front-end to iget that looks up inodes by file handle
4441da177e4SLinus Torvalds  * instead of inode number.
4451da177e4SLinus Torvalds  */
4461da177e4SLinus Torvalds struct inode *
nfs_fhget(struct super_block * sb,struct nfs_fh * fh,struct nfs_fattr * fattr)447cf7ab00aSAnna Schumaker nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
4481da177e4SLinus Torvalds {
4491da177e4SLinus Torvalds 	struct nfs_find_desc desc = {
4501da177e4SLinus Torvalds 		.fh	= fh,
4511da177e4SLinus Torvalds 		.fattr	= fattr
4521da177e4SLinus Torvalds 	};
45303f28e3aSTrond Myklebust 	struct inode *inode = ERR_PTR(-ENOENT);
454ce62b114STrond Myklebust 	u64 fattr_supported = NFS_SB(sb)->fattr_valid;
4551da177e4SLinus Torvalds 	unsigned long hash;
4561da177e4SLinus Torvalds 
4577ebb9315SBryan Schumaker 	nfs_attr_check_mountpoint(sb, fattr);
4587ebb9315SBryan Schumaker 
4592ef47eb1SAnna Schumaker 	if (nfs_attr_use_mounted_on_fileid(fattr))
4602ef47eb1SAnna Schumaker 		fattr->fileid = fattr->mounted_on_fileid;
4612ef47eb1SAnna Schumaker 	else if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0)
4621da177e4SLinus Torvalds 		goto out_no_inode;
4639e6e70f8STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0)
4641da177e4SLinus Torvalds 		goto out_no_inode;
4651da177e4SLinus Torvalds 
4661da177e4SLinus Torvalds 	hash = nfs_fattr_to_ino_t(fattr);
4671da177e4SLinus Torvalds 
46803f28e3aSTrond Myklebust 	inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc);
46903f28e3aSTrond Myklebust 	if (inode == NULL) {
47003f28e3aSTrond Myklebust 		inode = ERR_PTR(-ENOMEM);
4711da177e4SLinus Torvalds 		goto out_no_inode;
47203f28e3aSTrond Myklebust 	}
4731da177e4SLinus Torvalds 
4741da177e4SLinus Torvalds 	if (inode->i_state & I_NEW) {
4751da177e4SLinus Torvalds 		struct nfs_inode *nfsi = NFS_I(inode);
476b0c4fddcSTrond Myklebust 		unsigned long now = jiffies;
4771da177e4SLinus Torvalds 
4781da177e4SLinus Torvalds 		/* We set i_ino for the few things that still rely on it,
4791da177e4SLinus Torvalds 		 * such as stat(2) */
4801da177e4SLinus Torvalds 		inode->i_ino = hash;
4811da177e4SLinus Torvalds 
4821da177e4SLinus Torvalds 		/* We can't support update_atime(), since the server will reset it */
4831da177e4SLinus Torvalds 		inode->i_flags |= S_NOATIME|S_NOCMTIME;
4841da177e4SLinus Torvalds 		inode->i_mode = fattr->mode;
485821a868aSTrond Myklebust 		nfsi->cache_validity = 0;
48662ab460cSTrond Myklebust 		if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0
487ce62b114STrond Myklebust 				&& (fattr_supported & NFS_ATTR_FATTR_MODE))
488720869ebSTrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_MODE);
4891da177e4SLinus Torvalds 		/* Why so? Because we want revalidate for devices/FIFOs, and
4901da177e4SLinus Torvalds 		 * that's precisely what we have in nfs_file_inode_operations.
4911da177e4SLinus Torvalds 		 */
4928fa5c000SDavid Howells 		inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops;
4931da177e4SLinus Torvalds 		if (S_ISREG(inode->i_mode)) {
4941788ea6eSJeff Layton 			inode->i_fop = NFS_SB(sb)->nfs_client->rpc_ops->file_ops;
4951da177e4SLinus Torvalds 			inode->i_data.a_ops = &nfs_file_aops;
496e591b298STrond Myklebust 			nfs_inode_init_regular(nfsi);
4971da177e4SLinus Torvalds 		} else if (S_ISDIR(inode->i_mode)) {
4988fa5c000SDavid Howells 			inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops;
4991da177e4SLinus Torvalds 			inode->i_fop = &nfs_dir_operations;
50011de3b11STrond Myklebust 			inode->i_data.a_ops = &nfs_dir_aops;
501e591b298STrond Myklebust 			nfs_inode_init_dir(nfsi);
50255a97593STrond Myklebust 			/* Deal with crossing mountpoints */
5037ebb9315SBryan Schumaker 			if (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT ||
5047ebb9315SBryan Schumaker 					fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
5056b97fd3dSManoj Naik 				if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
5066b97fd3dSManoj Naik 					inode->i_op = &nfs_referral_inode_operations;
5076b97fd3dSManoj Naik 				else
50855a97593STrond Myklebust 					inode->i_op = &nfs_mountpoint_inode_operations;
50955a97593STrond Myklebust 				inode->i_fop = NULL;
51036d43a43SDavid Howells 				inode->i_flags |= S_AUTOMOUNT;
51155a97593STrond Myklebust 			}
51221fc61c7SAl Viro 		} else if (S_ISLNK(inode->i_mode)) {
5131da177e4SLinus Torvalds 			inode->i_op = &nfs_symlink_inode_operations;
51421fc61c7SAl Viro 			inode_nohighmem(inode);
51521fc61c7SAl Viro 		} else
5161da177e4SLinus Torvalds 			init_special_inode(inode, inode->i_mode, fattr->rdev);
5171da177e4SLinus Torvalds 
5189e6e70f8STrond Myklebust 		memset(&inode->i_atime, 0, sizeof(inode->i_atime));
5199e6e70f8STrond Myklebust 		memset(&inode->i_mtime, 0, sizeof(inode->i_mtime));
52055e04e9cSJeff Layton 		inode_set_ctime(inode, 0, 0);
5211eb5d98fSJeff Layton 		inode_set_iversion_raw(inode, 0);
5229e6e70f8STrond Myklebust 		inode->i_size = 0;
5236d6b77f1SMiklos Szeredi 		clear_nlink(inode);
5249ff593c4SEric W. Biederman 		inode->i_uid = make_kuid(&init_user_ns, -2);
5259ff593c4SEric W. Biederman 		inode->i_gid = make_kgid(&init_user_ns, -2);
5269e6e70f8STrond Myklebust 		inode->i_blocks = 0;
5272701d086SAndy Adamson 		nfsi->write_io = 0;
5282701d086SAndy Adamson 		nfsi->read_io = 0;
5299e6e70f8STrond Myklebust 
53033801147STrond Myklebust 		nfsi->read_cache_jiffies = fattr->time_start;
5314704f0e2STrond Myklebust 		nfsi->attr_gencount = fattr->gencount;
5329e6e70f8STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_ATIME)
533e86d5a02STrond Myklebust 			inode->i_atime = fattr->atime;
534ce62b114STrond Myklebust 		else if (fattr_supported & NFS_ATTR_FATTR_ATIME)
53516e14375STrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME);
5369e6e70f8STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_MTIME)
537e86d5a02STrond Myklebust 			inode->i_mtime = fattr->mtime;
538ce62b114STrond Myklebust 		else if (fattr_supported & NFS_ATTR_FATTR_MTIME)
53916e14375STrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME);
5409e6e70f8STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_CTIME)
54155e04e9cSJeff Layton 			inode_set_ctime_to_ts(inode, fattr->ctime);
542ce62b114STrond Myklebust 		else if (fattr_supported & NFS_ATTR_FATTR_CTIME)
54316e14375STrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_CTIME);
5449e6e70f8STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
5451eb5d98fSJeff Layton 			inode_set_iversion_raw(inode, fattr->change_attr);
546cd812599STrond Myklebust 		else
54716e14375STrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE);
5489e6e70f8STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_SIZE)
5491da177e4SLinus Torvalds 			inode->i_size = nfs_size_to_loff_t(fattr->size);
55062ab460cSTrond Myklebust 		else
55116e14375STrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_SIZE);
5529e6e70f8STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_NLINK)
553bfe86848SMiklos Szeredi 			set_nlink(inode, fattr->nlink);
554ce62b114STrond Myklebust 		else if (fattr_supported & NFS_ATTR_FATTR_NLINK)
555fabf2b34STrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_NLINK);
5569e6e70f8STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_OWNER)
5571da177e4SLinus Torvalds 			inode->i_uid = fattr->uid;
558ce62b114STrond Myklebust 		else if (fattr_supported & NFS_ATTR_FATTR_OWNER)
55916e14375STrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);
5609e6e70f8STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_GROUP)
5611da177e4SLinus Torvalds 			inode->i_gid = fattr->gid;
562ce62b114STrond Myklebust 		else if (fattr_supported & NFS_ATTR_FATTR_GROUP)
56316e14375STrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER);
5649e6e70f8STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
5659e6e70f8STrond Myklebust 			inode->i_blocks = fattr->du.nfs2.blocks;
566ce62b114STrond Myklebust 		else if (fattr_supported & NFS_ATTR_FATTR_BLOCKS_USED &&
567ce62b114STrond Myklebust 			 fattr->size != 0)
568ce62b114STrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS);
5699e6e70f8STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
5701da177e4SLinus Torvalds 			/*
5711da177e4SLinus Torvalds 			 * report the blocks in 512byte units
5721da177e4SLinus Torvalds 			 */
5731da177e4SLinus Torvalds 			inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
574ce62b114STrond Myklebust 		} else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED &&
575ce62b114STrond Myklebust 			   fattr->size != 0)
5764cdfeb64STrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS);
577821a868aSTrond Myklebust 
578dd225cb3SAnna Schumaker 		nfs_setsecurity(inode, fattr);
579aa9c2669SDavid Quigley 
5801da177e4SLinus Torvalds 		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
581b0c4fddcSTrond Myklebust 		nfsi->attrtimeo_timestamp = now;
5821c3c07e9STrond Myklebust 		nfsi->access_cache = RB_ROOT;
5831da177e4SLinus Torvalds 
584f1fe29b4SDavid Howells 		nfs_fscache_init_inode(inode);
585ef79c097SDavid Howells 
5861da177e4SLinus Torvalds 		unlock_new_inode(inode);
58726fde4dfSNeilBrown 	} else {
58826fde4dfSNeilBrown 		int err = nfs_refresh_inode(inode, fattr);
58926fde4dfSNeilBrown 		if (err < 0) {
59026fde4dfSNeilBrown 			iput(inode);
59126fde4dfSNeilBrown 			inode = ERR_PTR(err);
59226fde4dfSNeilBrown 			goto out_no_inode;
59326fde4dfSNeilBrown 		}
59426fde4dfSNeilBrown 	}
5951e8968c5SNiels de Vos 	dprintk("NFS: nfs_fhget(%s/%Lu fh_crc=0x%08x ct=%d)\n",
5961da177e4SLinus Torvalds 		inode->i_sb->s_id,
5971e8968c5SNiels de Vos 		(unsigned long long)NFS_FILEID(inode),
5984f1abd22SWeston Andros Adamson 		nfs_display_fhandle_hash(fh),
5991da177e4SLinus Torvalds 		atomic_read(&inode->i_count));
6001da177e4SLinus Torvalds 
6011da177e4SLinus Torvalds out:
6021da177e4SLinus Torvalds 	return inode;
6031da177e4SLinus Torvalds 
6041da177e4SLinus Torvalds out_no_inode:
60503f28e3aSTrond Myklebust 	dprintk("nfs_fhget: iget failed with error %ld\n", PTR_ERR(inode));
6061da177e4SLinus Torvalds 	goto out;
6071da177e4SLinus Torvalds }
60889d77c8fSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_fhget);
6091da177e4SLinus Torvalds 
610536e43d1STrond Myklebust #define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE|ATTR_OPEN)
6111da177e4SLinus Torvalds 
6121da177e4SLinus Torvalds int
nfs_setattr(struct mnt_idmap * idmap,struct dentry * dentry,struct iattr * attr)613c1632a0fSChristian Brauner nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
614549c7297SChristian Brauner 	    struct iattr *attr)
6151da177e4SLinus Torvalds {
6162b0143b5SDavid Howells 	struct inode *inode = d_inode(dentry);
617987f8dfcSTrond Myklebust 	struct nfs_fattr *fattr;
618ae57ca0fSKinglong Mee 	int error = 0;
6191da177e4SLinus Torvalds 
62091d5b470SChuck Lever 	nfs_inc_stats(inode, NFSIOS_VFSSETATTR);
62191d5b470SChuck Lever 
622188b95ddSJeff Layton 	/* skip mode change if it's just for clearing setuid/setgid */
623188b95ddSJeff Layton 	if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
624188b95ddSJeff Layton 		attr->ia_valid &= ~ATTR_MODE;
625188b95ddSJeff Layton 
6261da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_SIZE) {
62708a899d5SChristoph Hellwig 		BUG_ON(!S_ISREG(inode->i_mode));
62808a899d5SChristoph Hellwig 
629ae57ca0fSKinglong Mee 		error = inode_newsize_ok(inode, attr->ia_size);
630ae57ca0fSKinglong Mee 		if (error)
631ae57ca0fSKinglong Mee 			return error;
632ae57ca0fSKinglong Mee 
633ae57ca0fSKinglong Mee 		if (attr->ia_size == i_size_read(inode))
6341da177e4SLinus Torvalds 			attr->ia_valid &= ~ATTR_SIZE;
6351da177e4SLinus Torvalds 	}
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds 	/* Optimization: if the end result is no change, don't RPC */
6381f9f4328STrond Myklebust 	if (((attr->ia_valid & NFS_VALID_ATTRS) & ~(ATTR_FILE|ATTR_OPEN)) == 0)
6391da177e4SLinus Torvalds 		return 0;
6401da177e4SLinus Torvalds 
641f4ce1299STrond Myklebust 	trace_nfs_setattr_enter(inode);
642f4ce1299STrond Myklebust 
643755c1e20STrond Myklebust 	/* Write all dirty data */
6444d346beaSTrond Myklebust 	if (S_ISREG(inode->i_mode))
6454d346beaSTrond Myklebust 		nfs_sync_inode(inode);
646987f8dfcSTrond Myklebust 
6471b00ad65SAnna Schumaker 	fattr = nfs_alloc_fattr_with_label(NFS_SERVER(inode));
648ae57ca0fSKinglong Mee 	if (fattr == NULL) {
649ae57ca0fSKinglong Mee 		error = -ENOMEM;
650987f8dfcSTrond Myklebust 		goto out;
651ae57ca0fSKinglong Mee 	}
652ae57ca0fSKinglong Mee 
653987f8dfcSTrond Myklebust 	error = NFS_PROTO(inode)->setattr(dentry, fattr, attr);
65465e4308dSTrond Myklebust 	if (error == 0)
655aa9c2669SDavid Quigley 		error = nfs_refresh_inode(inode, fattr);
656987f8dfcSTrond Myklebust 	nfs_free_fattr(fattr);
657987f8dfcSTrond Myklebust out:
658f4ce1299STrond Myklebust 	trace_nfs_setattr_exit(inode, error);
65965e4308dSTrond Myklebust 	return error;
66065e4308dSTrond Myklebust }
661ddda8e0aSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_setattr);
66265e4308dSTrond Myklebust 
66365e4308dSTrond Myklebust /**
664a3d01454STrond Myklebust  * nfs_vmtruncate - unmap mappings "freed" by truncate() syscall
665a3d01454STrond Myklebust  * @inode: inode of the file used
666a3d01454STrond Myklebust  * @offset: file offset to start truncating
667a3d01454STrond Myklebust  *
668a3d01454STrond Myklebust  * This is a copy of the common vmtruncate, but with the locking
669a3d01454STrond Myklebust  * corrected to take into account the fact that NFS requires
670a3d01454STrond Myklebust  * inode->i_size to be updated under the inode->i_lock.
671f044636dSTrond Myklebust  * Note: must be called with inode->i_lock held!
672a3d01454STrond Myklebust  */
nfs_vmtruncate(struct inode * inode,loff_t offset)673a3d01454STrond Myklebust static int nfs_vmtruncate(struct inode * inode, loff_t offset)
674a3d01454STrond Myklebust {
675c08d3b0eSnpiggin@suse.de 	int err;
676a3d01454STrond Myklebust 
677c08d3b0eSnpiggin@suse.de 	err = inode_newsize_ok(inode, offset);
678c08d3b0eSnpiggin@suse.de 	if (err)
679c08d3b0eSnpiggin@suse.de 		goto out;
680a3d01454STrond Myklebust 
681110cb2d2SChuck Lever 	trace_nfs_size_truncate(inode, offset);
682a3d01454STrond Myklebust 	i_size_write(inode, offset);
6836edf9609STrond Myklebust 	/* Optimisation */
6843db63daaSNeilBrown 	if (offset == 0) {
6853db63daaSNeilBrown 		NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA;
6863db63daaSNeilBrown 		nfs_ooo_clear(NFS_I(inode));
6873db63daaSNeilBrown 	}
688f6cdfa6dSTrond Myklebust 	NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_SIZE;
689a3d01454STrond Myklebust 
690f044636dSTrond Myklebust 	spin_unlock(&inode->i_lock);
6917caef267SKirill A. Shutemov 	truncate_pagecache(inode, offset);
692f044636dSTrond Myklebust 	spin_lock(&inode->i_lock);
693c08d3b0eSnpiggin@suse.de out:
694c08d3b0eSnpiggin@suse.de 	return err;
695a3d01454STrond Myklebust }
696a3d01454STrond Myklebust 
697a3d01454STrond Myklebust /**
69865e4308dSTrond Myklebust  * nfs_setattr_update_inode - Update inode metadata after a setattr call.
69965e4308dSTrond Myklebust  * @inode: pointer to struct inode
70065e4308dSTrond Myklebust  * @attr: pointer to struct iattr
70116e14375STrond Myklebust  * @fattr: pointer to struct nfs_fattr
70265e4308dSTrond Myklebust  *
70365e4308dSTrond Myklebust  * Note: we do this in the *proc.c in order to ensure that
70465e4308dSTrond Myklebust  *       it works for things like exclusive creates too.
70565e4308dSTrond Myklebust  */
nfs_setattr_update_inode(struct inode * inode,struct iattr * attr,struct nfs_fattr * fattr)706f044636dSTrond Myklebust void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
707f044636dSTrond Myklebust 		struct nfs_fattr *fattr)
70865e4308dSTrond Myklebust {
709f044636dSTrond Myklebust 	/* Barrier: bump the attribute generation count. */
710f044636dSTrond Myklebust 	nfs_fattr_set_barrier(fattr);
711f044636dSTrond Myklebust 
7122f28ea61STrond Myklebust 	spin_lock(&inode->i_lock);
713f044636dSTrond Myklebust 	NFS_I(inode)->attr_gencount = fattr->gencount;
7146a97d02dSTrond Myklebust 	if ((attr->ia_valid & ATTR_SIZE) != 0) {
7154cdfeb64STrond Myklebust 		nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME |
7164cdfeb64STrond Myklebust 						     NFS_INO_INVALID_BLOCKS);
7176a97d02dSTrond Myklebust 		nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
7186a97d02dSTrond Myklebust 		nfs_vmtruncate(inode, attr->ia_size);
7196a97d02dSTrond Myklebust 	}
720f044636dSTrond Myklebust 	if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
7216a97d02dSTrond Myklebust 		NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_CTIME;
7221f9f4328STrond Myklebust 		if ((attr->ia_valid & ATTR_KILL_SUID) != 0 &&
7231f9f4328STrond Myklebust 		    inode->i_mode & S_ISUID)
7241f9f4328STrond Myklebust 			inode->i_mode &= ~S_ISUID;
7254f704d9aSChristian Brauner 		if (setattr_should_drop_sgid(&nop_mnt_idmap, inode))
7261f9f4328STrond Myklebust 			inode->i_mode &= ~S_ISGID;
7271da177e4SLinus Torvalds 		if ((attr->ia_valid & ATTR_MODE) != 0) {
72865e4308dSTrond Myklebust 			int mode = attr->ia_mode & S_IALLUGO;
72965e4308dSTrond Myklebust 			mode |= inode->i_mode & ~S_IALLUGO;
7301da177e4SLinus Torvalds 			inode->i_mode = mode;
7311da177e4SLinus Torvalds 		}
7321da177e4SLinus Torvalds 		if ((attr->ia_valid & ATTR_UID) != 0)
7331da177e4SLinus Torvalds 			inode->i_uid = attr->ia_uid;
7341da177e4SLinus Torvalds 		if ((attr->ia_valid & ATTR_GID) != 0)
7351da177e4SLinus Torvalds 			inode->i_gid = attr->ia_gid;
7366a97d02dSTrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_CTIME)
73755e04e9cSJeff Layton 			inode_set_ctime_to_ts(inode, fattr->ctime);
7386a97d02dSTrond Myklebust 		else
7396a97d02dSTrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE
7406a97d02dSTrond Myklebust 					| NFS_INO_INVALID_CTIME);
7416edf9609STrond Myklebust 		nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS
7426edf9609STrond Myklebust 				| NFS_INO_INVALID_ACL);
74365e4308dSTrond Myklebust 	}
7446a97d02dSTrond Myklebust 	if (attr->ia_valid & (ATTR_ATIME_SET|ATTR_ATIME)) {
7456a97d02dSTrond Myklebust 		NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_ATIME
7466a97d02dSTrond Myklebust 				| NFS_INO_INVALID_CTIME);
7476a97d02dSTrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_ATIME)
748e86d5a02STrond Myklebust 			inode->i_atime = fattr->atime;
7496a97d02dSTrond Myklebust 		else if (attr->ia_valid & ATTR_ATIME_SET)
7506a97d02dSTrond Myklebust 			inode->i_atime = attr->ia_atime;
7516a97d02dSTrond Myklebust 		else
7526a97d02dSTrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME);
7536a97d02dSTrond Myklebust 
7546a97d02dSTrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_CTIME)
75555e04e9cSJeff Layton 			inode_set_ctime_to_ts(inode, fattr->ctime);
7566a97d02dSTrond Myklebust 		else
7576a97d02dSTrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE
7586a97d02dSTrond Myklebust 					| NFS_INO_INVALID_CTIME);
7596a97d02dSTrond Myklebust 	}
7606a97d02dSTrond Myklebust 	if (attr->ia_valid & (ATTR_MTIME_SET|ATTR_MTIME)) {
7616a97d02dSTrond Myklebust 		NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_MTIME
7626a97d02dSTrond Myklebust 				| NFS_INO_INVALID_CTIME);
7636a97d02dSTrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_MTIME)
764e86d5a02STrond Myklebust 			inode->i_mtime = fattr->mtime;
7656a97d02dSTrond Myklebust 		else if (attr->ia_valid & ATTR_MTIME_SET)
7666a97d02dSTrond Myklebust 			inode->i_mtime = attr->ia_mtime;
7676a97d02dSTrond Myklebust 		else
76816e14375STrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME);
7696a97d02dSTrond Myklebust 
7706a97d02dSTrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_CTIME)
77155e04e9cSJeff Layton 			inode_set_ctime_to_ts(inode, fattr->ctime);
7726a97d02dSTrond Myklebust 		else
7736a97d02dSTrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE
7746a97d02dSTrond Myklebust 					| NFS_INO_INVALID_CTIME);
7751da177e4SLinus Torvalds 	}
776616c3196SJeff Layton 	if (fattr->valid)
777f044636dSTrond Myklebust 		nfs_update_inode(inode, fattr);
778f044636dSTrond Myklebust 	spin_unlock(&inode->i_lock);
7791da177e4SLinus Torvalds }
780ddda8e0aSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
7811da177e4SLinus Torvalds 
782ad1e109aSTrond Myklebust /*
783ad1e109aSTrond Myklebust  * Don't request help from readdirplus if the file is being written to,
784ad1e109aSTrond Myklebust  * or if attribute caching is turned off
785ad1e109aSTrond Myklebust  */
nfs_getattr_readdirplus_enable(const struct inode * inode)786ad1e109aSTrond Myklebust static bool nfs_getattr_readdirplus_enable(const struct inode *inode)
787ad1e109aSTrond Myklebust {
788ad1e109aSTrond Myklebust 	return nfs_server_capable(inode, NFS_CAP_READDIRPLUS) &&
789ad1e109aSTrond Myklebust 	       !nfs_have_writebacks(inode) && NFS_MAXATTRTIMEO(inode) > 5 * HZ;
790ad1e109aSTrond Myklebust }
791ad1e109aSTrond Myklebust 
nfs_readdirplus_parent_cache_miss(struct dentry * dentry)7921bcf4c5cSTrond Myklebust static void nfs_readdirplus_parent_cache_miss(struct dentry *dentry)
793311324adSTrond Myklebust {
794ad1e109aSTrond Myklebust 	if (!IS_ROOT(dentry)) {
795ad1e109aSTrond Myklebust 		struct dentry *parent = dget_parent(dentry);
796230bc98fSTrond Myklebust 		nfs_readdir_record_entry_cache_miss(d_inode(parent));
797311324adSTrond Myklebust 		dput(parent);
798311324adSTrond Myklebust 	}
799ad1e109aSTrond Myklebust }
800311324adSTrond Myklebust 
nfs_readdirplus_parent_cache_hit(struct dentry * dentry)8011bcf4c5cSTrond Myklebust static void nfs_readdirplus_parent_cache_hit(struct dentry *dentry)
8021bcf4c5cSTrond Myklebust {
803ad1e109aSTrond Myklebust 	if (!IS_ROOT(dentry)) {
804ad1e109aSTrond Myklebust 		struct dentry *parent = dget_parent(dentry);
805230bc98fSTrond Myklebust 		nfs_readdir_record_entry_cache_hit(d_inode(parent));
8061bcf4c5cSTrond Myklebust 		dput(parent);
8071bcf4c5cSTrond Myklebust 	}
808ad1e109aSTrond Myklebust }
8091bcf4c5cSTrond Myklebust 
nfs_get_valid_attrmask(struct inode * inode)81063cdd7edSTrond Myklebust static u32 nfs_get_valid_attrmask(struct inode *inode)
811311324adSTrond Myklebust {
81263cdd7edSTrond Myklebust 	unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
81363cdd7edSTrond Myklebust 	u32 reply_mask = STATX_INO | STATX_TYPE;
81463cdd7edSTrond Myklebust 
81563cdd7edSTrond Myklebust 	if (!(cache_validity & NFS_INO_INVALID_ATIME))
81663cdd7edSTrond Myklebust 		reply_mask |= STATX_ATIME;
81763cdd7edSTrond Myklebust 	if (!(cache_validity & NFS_INO_INVALID_CTIME))
81863cdd7edSTrond Myklebust 		reply_mask |= STATX_CTIME;
81963cdd7edSTrond Myklebust 	if (!(cache_validity & NFS_INO_INVALID_MTIME))
82063cdd7edSTrond Myklebust 		reply_mask |= STATX_MTIME;
82163cdd7edSTrond Myklebust 	if (!(cache_validity & NFS_INO_INVALID_SIZE))
82263cdd7edSTrond Myklebust 		reply_mask |= STATX_SIZE;
823fabf2b34STrond Myklebust 	if (!(cache_validity & NFS_INO_INVALID_NLINK))
824fabf2b34STrond Myklebust 		reply_mask |= STATX_NLINK;
825720869ebSTrond Myklebust 	if (!(cache_validity & NFS_INO_INVALID_MODE))
826720869ebSTrond Myklebust 		reply_mask |= STATX_MODE;
82763cdd7edSTrond Myklebust 	if (!(cache_validity & NFS_INO_INVALID_OTHER))
828720869ebSTrond Myklebust 		reply_mask |= STATX_UID | STATX_GID;
82963cdd7edSTrond Myklebust 	if (!(cache_validity & NFS_INO_INVALID_BLOCKS))
83063cdd7edSTrond Myklebust 		reply_mask |= STATX_BLOCKS;
83161a968b4SJeff Layton 	if (!(cache_validity & NFS_INO_INVALID_CHANGE))
83261a968b4SJeff Layton 		reply_mask |= STATX_CHANGE_COOKIE;
83363cdd7edSTrond Myklebust 	return reply_mask;
834311324adSTrond Myklebust }
835311324adSTrond Myklebust 
nfs_getattr(struct mnt_idmap * idmap,const struct path * path,struct kstat * stat,u32 request_mask,unsigned int query_flags)836b74d24f7SChristian Brauner int nfs_getattr(struct mnt_idmap *idmap, const struct path *path,
837549c7297SChristian Brauner 		struct kstat *stat, u32 request_mask, unsigned int query_flags)
8381da177e4SLinus Torvalds {
839a528d35eSDavid Howells 	struct inode *inode = d_inode(path->dentry);
8409ccee940STrond Myklebust 	struct nfs_server *server = NFS_SERVER(inode);
8419ccee940STrond Myklebust 	unsigned long cache_validity;
84216caf5b6SJan Kara 	int err = 0;
8439ccee940STrond Myklebust 	bool force_sync = query_flags & AT_STATX_FORCE_SYNC;
8449ccee940STrond Myklebust 	bool do_update = false;
845ad1e109aSTrond Myklebust 	bool readdirplus_enabled = nfs_getattr_readdirplus_enable(inode);
8461da177e4SLinus Torvalds 
847f4ce1299STrond Myklebust 	trace_nfs_getattr_enter(inode);
8489ccee940STrond Myklebust 
8494eb6a823STrond Myklebust 	request_mask &= STATX_TYPE | STATX_MODE | STATX_NLINK | STATX_UID |
8504eb6a823STrond Myklebust 			STATX_GID | STATX_ATIME | STATX_MTIME | STATX_CTIME |
851cded49baSJeff Layton 			STATX_INO | STATX_SIZE | STATX_BLOCKS |
85261a968b4SJeff Layton 			STATX_CHANGE_COOKIE;
8534eb6a823STrond Myklebust 
854ac7cbb22STrond Myklebust 	if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) {
855ad1e109aSTrond Myklebust 		if (readdirplus_enabled)
856ac7cbb22STrond Myklebust 			nfs_readdirplus_parent_cache_hit(path->dentry);
85763cdd7edSTrond Myklebust 		goto out_no_revalidate;
858ac7cbb22STrond Myklebust 	}
8599ccee940STrond Myklebust 
86061a968b4SJeff Layton 	/* Flush out writes to the server in order to update c/mtime/version.  */
86161a968b4SJeff Layton 	if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_CHANGE_COOKIE)) &&
862d19e0183STrond Myklebust 	    S_ISREG(inode->i_mode))
863d19e0183STrond Myklebust 		filemap_write_and_wait(inode->i_mapping);
864fc33a7bbSChristoph Hellwig 
865fc33a7bbSChristoph Hellwig 	/*
866fc33a7bbSChristoph Hellwig 	 * We may force a getattr if the user cares about atime.
867fc33a7bbSChristoph Hellwig 	 *
868fc33a7bbSChristoph Hellwig 	 * Note that we only have to check the vfsmount flags here:
869fc33a7bbSChristoph Hellwig 	 *  - NFS always sets S_NOATIME by so checking it would give a
870fc33a7bbSChristoph Hellwig 	 *    bogus result
8711751e8a6SLinus Torvalds 	 *  - NFS never sets SB_NOATIME or SB_NODIRATIME so there is
872fc33a7bbSChristoph Hellwig 	 *    no point in checking those.
873fc33a7bbSChristoph Hellwig 	 */
874a528d35eSDavid Howells 	if ((path->mnt->mnt_flags & MNT_NOATIME) ||
875a528d35eSDavid Howells 	    ((path->mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
8769ccee940STrond Myklebust 		request_mask &= ~STATX_ATIME;
877fc33a7bbSChristoph Hellwig 
8789ccee940STrond Myklebust 	/* Is the user requesting attributes that might need revalidation? */
8799ccee940STrond Myklebust 	if (!(request_mask & (STATX_MODE|STATX_NLINK|STATX_ATIME|STATX_CTIME|
8809ccee940STrond Myklebust 					STATX_MTIME|STATX_UID|STATX_GID|
88161a968b4SJeff Layton 					STATX_SIZE|STATX_BLOCKS|
88261a968b4SJeff Layton 					STATX_CHANGE_COOKIE)))
8839ccee940STrond Myklebust 		goto out_no_revalidate;
884311324adSTrond Myklebust 
8859ccee940STrond Myklebust 	/* Check whether the cached attributes are stale */
8869ccee940STrond Myklebust 	do_update |= force_sync || nfs_attribute_cache_expired(inode);
8879ccee940STrond Myklebust 	cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
888e8764a6fSTrond Myklebust 	do_update |= cache_validity & NFS_INO_INVALID_CHANGE;
8899ccee940STrond Myklebust 	if (request_mask & STATX_ATIME)
8909ccee940STrond Myklebust 		do_update |= cache_validity & NFS_INO_INVALID_ATIME;
891e8764a6fSTrond Myklebust 	if (request_mask & STATX_CTIME)
892e8764a6fSTrond Myklebust 		do_update |= cache_validity & NFS_INO_INVALID_CTIME;
893e8764a6fSTrond Myklebust 	if (request_mask & STATX_MTIME)
894e8764a6fSTrond Myklebust 		do_update |= cache_validity & NFS_INO_INVALID_MTIME;
895e8764a6fSTrond Myklebust 	if (request_mask & STATX_SIZE)
896e8764a6fSTrond Myklebust 		do_update |= cache_validity & NFS_INO_INVALID_SIZE;
897fabf2b34STrond Myklebust 	if (request_mask & STATX_NLINK)
898fabf2b34STrond Myklebust 		do_update |= cache_validity & NFS_INO_INVALID_NLINK;
899720869ebSTrond Myklebust 	if (request_mask & STATX_MODE)
900720869ebSTrond Myklebust 		do_update |= cache_validity & NFS_INO_INVALID_MODE;
901720869ebSTrond Myklebust 	if (request_mask & (STATX_UID | STATX_GID))
902e8764a6fSTrond Myklebust 		do_update |= cache_validity & NFS_INO_INVALID_OTHER;
9033a39e778SZheng Bin 	if (request_mask & STATX_BLOCKS)
9043a39e778SZheng Bin 		do_update |= cache_validity & NFS_INO_INVALID_BLOCKS;
90563cdd7edSTrond Myklebust 
9069ccee940STrond Myklebust 	if (do_update) {
907ad1e109aSTrond Myklebust 		if (readdirplus_enabled)
908a528d35eSDavid Howells 			nfs_readdirplus_parent_cache_miss(path->dentry);
909311324adSTrond Myklebust 		err = __nfs_revalidate_inode(server, inode);
9109ccee940STrond Myklebust 		if (err)
9119ccee940STrond Myklebust 			goto out;
912ad1e109aSTrond Myklebust 	} else if (readdirplus_enabled)
913a528d35eSDavid Howells 		nfs_readdirplus_parent_cache_hit(path->dentry);
9149ccee940STrond Myklebust out_no_revalidate:
9159ccee940STrond Myklebust 	/* Only return attributes that were revalidated. */
91663cdd7edSTrond Myklebust 	stat->result_mask = nfs_get_valid_attrmask(inode) | request_mask;
91763cdd7edSTrond Myklebust 
9180d72b928SJeff Layton 	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
919f43bf0beSTrond Myklebust 	stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
92061a968b4SJeff Layton 	stat->change_cookie = inode_peek_iversion_raw(inode);
92161a968b4SJeff Layton 	stat->attributes_mask |= STATX_ATTR_CHANGE_MONOTONIC;
92261a968b4SJeff Layton 	if (server->change_attr_type != NFS4_CHANGE_TYPE_IS_UNDEFINED)
92361a968b4SJeff Layton 		stat->attributes |= STATX_ATTR_CHANGE_MONOTONIC;
9247ef5ca4fSNeilBrown 	if (S_ISDIR(inode->i_mode))
9257ef5ca4fSNeilBrown 		stat->blksize = NFS_SERVER(inode)->dtsize;
926acdc53b2STrond Myklebust out:
927f4ce1299STrond Myklebust 	trace_nfs_getattr_exit(inode, err);
9281da177e4SLinus Torvalds 	return err;
9291da177e4SLinus Torvalds }
930ddda8e0aSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_getattr);
9311da177e4SLinus Torvalds 
nfs_init_lock_context(struct nfs_lock_context * l_ctx)932f11ac8dbSTrond Myklebust static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
933f11ac8dbSTrond Myklebust {
9342f62b5aaSElena Reshetova 	refcount_set(&l_ctx->count, 1);
935d51fdb87SNeilBrown 	l_ctx->lockowner = current->files;
936f11ac8dbSTrond Myklebust 	INIT_LIST_HEAD(&l_ctx->list);
937210c7c17SBenjamin Coddington 	atomic_set(&l_ctx->io_count, 0);
938f11ac8dbSTrond Myklebust }
939f11ac8dbSTrond Myklebust 
__nfs_find_lock_context(struct nfs_open_context * ctx)940f11ac8dbSTrond Myklebust static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx)
941f11ac8dbSTrond Myklebust {
9421db97eaaSTrond Myklebust 	struct nfs_lock_context *pos;
943f11ac8dbSTrond Myklebust 
9441db97eaaSTrond Myklebust 	list_for_each_entry_rcu(pos, &ctx->lock_context.list, list) {
945d51fdb87SNeilBrown 		if (pos->lockowner != current->files)
946f11ac8dbSTrond Myklebust 			continue;
9471db97eaaSTrond Myklebust 		if (refcount_inc_not_zero(&pos->count))
948f11ac8dbSTrond Myklebust 			return pos;
9491db97eaaSTrond Myklebust 	}
950f11ac8dbSTrond Myklebust 	return NULL;
951f11ac8dbSTrond Myklebust }
952f11ac8dbSTrond Myklebust 
nfs_get_lock_context(struct nfs_open_context * ctx)953f11ac8dbSTrond Myklebust struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx)
954f11ac8dbSTrond Myklebust {
955f11ac8dbSTrond Myklebust 	struct nfs_lock_context *res, *new = NULL;
9562b0143b5SDavid Howells 	struct inode *inode = d_inode(ctx->dentry);
957f11ac8dbSTrond Myklebust 
9581db97eaaSTrond Myklebust 	rcu_read_lock();
959f11ac8dbSTrond Myklebust 	res = __nfs_find_lock_context(ctx);
9601db97eaaSTrond Myklebust 	rcu_read_unlock();
961f11ac8dbSTrond Myklebust 	if (res == NULL) {
962d7867712STrond Myklebust 		new = kmalloc(sizeof(*new), GFP_KERNEL_ACCOUNT);
963f11ac8dbSTrond Myklebust 		if (new == NULL)
964b3c54de6STrond Myklebust 			return ERR_PTR(-ENOMEM);
965f11ac8dbSTrond Myklebust 		nfs_init_lock_context(new);
966f11ac8dbSTrond Myklebust 		spin_lock(&inode->i_lock);
967f11ac8dbSTrond Myklebust 		res = __nfs_find_lock_context(ctx);
968f11ac8dbSTrond Myklebust 		if (res == NULL) {
96915494511STrond Myklebust 			new->open_context = get_nfs_open_context(ctx);
97015494511STrond Myklebust 			if (new->open_context) {
97115494511STrond Myklebust 				list_add_tail_rcu(&new->list,
97215494511STrond Myklebust 						&ctx->lock_context.list);
973f11ac8dbSTrond Myklebust 				res = new;
974f11ac8dbSTrond Myklebust 				new = NULL;
97515494511STrond Myklebust 			} else
97615494511STrond Myklebust 				res = ERR_PTR(-EBADF);
977f11ac8dbSTrond Myklebust 		}
978f11ac8dbSTrond Myklebust 		spin_unlock(&inode->i_lock);
979f11ac8dbSTrond Myklebust 		kfree(new);
9801db97eaaSTrond Myklebust 	}
981f11ac8dbSTrond Myklebust 	return res;
982f11ac8dbSTrond Myklebust }
9831c6dcbe5SAnna Schumaker EXPORT_SYMBOL_GPL(nfs_get_lock_context);
984f11ac8dbSTrond Myklebust 
nfs_put_lock_context(struct nfs_lock_context * l_ctx)985f11ac8dbSTrond Myklebust void nfs_put_lock_context(struct nfs_lock_context *l_ctx)
986f11ac8dbSTrond Myklebust {
987f11ac8dbSTrond Myklebust 	struct nfs_open_context *ctx = l_ctx->open_context;
9882b0143b5SDavid Howells 	struct inode *inode = d_inode(ctx->dentry);
989f11ac8dbSTrond Myklebust 
9902f62b5aaSElena Reshetova 	if (!refcount_dec_and_lock(&l_ctx->count, &inode->i_lock))
991f11ac8dbSTrond Myklebust 		return;
9921db97eaaSTrond Myklebust 	list_del_rcu(&l_ctx->list);
993f11ac8dbSTrond Myklebust 	spin_unlock(&inode->i_lock);
99415494511STrond Myklebust 	put_nfs_open_context(ctx);
9951db97eaaSTrond Myklebust 	kfree_rcu(l_ctx, rcu_head);
996f11ac8dbSTrond Myklebust }
9971c6dcbe5SAnna Schumaker EXPORT_SYMBOL_GPL(nfs_put_lock_context);
998f11ac8dbSTrond Myklebust 
9997fe5c398STrond Myklebust /**
10007fe5c398STrond Myklebust  * nfs_close_context - Common close_context() routine NFSv2/v3
10017fe5c398STrond Myklebust  * @ctx: pointer to context
10027fe5c398STrond Myklebust  * @is_sync: is this a synchronous close
10037fe5c398STrond Myklebust  *
10045cf9d706STrond Myklebust  * Ensure that the attributes are up to date if we're mounted
10055cf9d706STrond Myklebust  * with close-to-open semantics and we have cached data that will
10065cf9d706STrond Myklebust  * need to be revalidated on open.
10077fe5c398STrond Myklebust  */
nfs_close_context(struct nfs_open_context * ctx,int is_sync)10087fe5c398STrond Myklebust void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
10097fe5c398STrond Myklebust {
10105cf9d706STrond Myklebust 	struct nfs_inode *nfsi;
10117fe5c398STrond Myklebust 	struct inode *inode;
10127fe5c398STrond Myklebust 
10137fe5c398STrond Myklebust 	if (!(ctx->mode & FMODE_WRITE))
10147fe5c398STrond Myklebust 		return;
10157fe5c398STrond Myklebust 	if (!is_sync)
10167fe5c398STrond Myklebust 		return;
10172b0143b5SDavid Howells 	inode = d_inode(ctx->dentry);
101858ff4184STrond Myklebust 	if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
101958ff4184STrond Myklebust 		return;
10205cf9d706STrond Myklebust 	nfsi = NFS_I(inode);
10215cf9d706STrond Myklebust 	if (inode->i_mapping->nrpages == 0)
10225cf9d706STrond Myklebust 		return;
10235cf9d706STrond Myklebust 	if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
10245cf9d706STrond Myklebust 		return;
10255cf9d706STrond Myklebust 	if (!list_empty(&nfsi->open_files))
10267fe5c398STrond Myklebust 		return;
10271f3208b2STrond Myklebust 	if (NFS_SERVER(inode)->flags & NFS_MOUNT_NOCTO)
10287fe5c398STrond Myklebust 		return;
10291f3208b2STrond Myklebust 	nfs_revalidate_inode(inode,
10301f3208b2STrond Myklebust 			     NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE);
10317fe5c398STrond Myklebust }
1032ddda8e0aSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_close_context);
10337fe5c398STrond Myklebust 
alloc_nfs_open_context(struct dentry * dentry,fmode_t f_mode,struct file * filp)1034532d4defSNeilBrown struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry,
1035532d4defSNeilBrown 						fmode_t f_mode,
1036532d4defSNeilBrown 						struct file *filp)
10371da177e4SLinus Torvalds {
10381da177e4SLinus Torvalds 	struct nfs_open_context *ctx;
10391da177e4SLinus Torvalds 
1040d7867712STrond Myklebust 	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT);
10411d179d6bSTrond Myklebust 	if (!ctx)
10425ede7b1cSAl Viro 		return ERR_PTR(-ENOMEM);
10433d4ff43dSAl Viro 	nfs_sb_active(dentry->d_sb);
10443d4ff43dSAl Viro 	ctx->dentry = dget(dentry);
10451d179d6bSTrond Myklebust 	if (filp)
10461d179d6bSTrond Myklebust 		ctx->cred = get_cred(filp->f_cred);
10471d179d6bSTrond Myklebust 	else
10481d179d6bSTrond Myklebust 		ctx->cred = get_current_cred();
1049ca05cbaeSTrond Myklebust 	rcu_assign_pointer(ctx->ll_cred, NULL);
10501da177e4SLinus Torvalds 	ctx->state = NULL;
1051cd9a1c0eSTrond Myklebust 	ctx->mode = f_mode;
105266d3aac0SJeff Layton 	ctx->flags = 0;
10531da177e4SLinus Torvalds 	ctx->error = 0;
1054532d4defSNeilBrown 	ctx->flock_owner = (fl_owner_t)filp;
1055f11ac8dbSTrond Myklebust 	nfs_init_lock_context(&ctx->lock_context);
1056f11ac8dbSTrond Myklebust 	ctx->lock_context.open_context = ctx;
10575c78f58eSTrond Myklebust 	INIT_LIST_HEAD(&ctx->list);
105882be417aSAndy Adamson 	ctx->mdsthreshold = NULL;
10591da177e4SLinus Torvalds 	return ctx;
10601da177e4SLinus Torvalds }
106189d77c8fSBryan Schumaker EXPORT_SYMBOL_GPL(alloc_nfs_open_context);
10621da177e4SLinus Torvalds 
get_nfs_open_context(struct nfs_open_context * ctx)10631da177e4SLinus Torvalds struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
10641da177e4SLinus Torvalds {
10650de43976STrond Myklebust 	if (ctx != NULL && refcount_inc_not_zero(&ctx->lock_context.count))
10661da177e4SLinus Torvalds 		return ctx;
10670de43976STrond Myklebust 	return NULL;
10681da177e4SLinus Torvalds }
106989d77c8fSBryan Schumaker EXPORT_SYMBOL_GPL(get_nfs_open_context);
10701da177e4SLinus Torvalds 
__put_nfs_open_context(struct nfs_open_context * ctx,int is_sync)10717fe5c398STrond Myklebust static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
10721da177e4SLinus Torvalds {
10732b0143b5SDavid Howells 	struct inode *inode = d_inode(ctx->dentry);
10743d4ff43dSAl Viro 	struct super_block *sb = ctx->dentry->d_sb;
10755e11934dSTrond Myklebust 
10760de43976STrond Myklebust 	if (!refcount_dec_and_test(&ctx->lock_context.count))
10770de43976STrond Myklebust 		return;
10785c78f58eSTrond Myklebust 	if (!list_empty(&ctx->list)) {
10790de43976STrond Myklebust 		spin_lock(&inode->i_lock);
10800de43976STrond Myklebust 		list_del_rcu(&ctx->list);
10811da177e4SLinus Torvalds 		spin_unlock(&inode->i_lock);
10820de43976STrond Myklebust 	}
10835c78f58eSTrond Myklebust 	if (inode != NULL)
10845c78f58eSTrond Myklebust 		NFS_PROTO(inode)->close_context(ctx, is_sync);
1085a52458b4SNeilBrown 	put_cred(ctx->cred);
10863d4ff43dSAl Viro 	dput(ctx->dentry);
10873d4ff43dSAl Viro 	nfs_sb_deactive(sb);
1088ca05cbaeSTrond Myklebust 	put_rpccred(rcu_dereference_protected(ctx->ll_cred, 1));
108982be417aSAndy Adamson 	kfree(ctx->mdsthreshold);
10900de43976STrond Myklebust 	kfree_rcu(ctx, rcu_head);
10911da177e4SLinus Torvalds }
10923bec63dbSTrond Myklebust 
put_nfs_open_context(struct nfs_open_context * ctx)1093a49c3c77STrond Myklebust void put_nfs_open_context(struct nfs_open_context *ctx)
1094a49c3c77STrond Myklebust {
1095a49c3c77STrond Myklebust 	__put_nfs_open_context(ctx, 0);
1096a49c3c77STrond Myklebust }
109789d77c8fSBryan Schumaker EXPORT_SYMBOL_GPL(put_nfs_open_context);
1098a49c3c77STrond Myklebust 
put_nfs_open_context_sync(struct nfs_open_context * ctx)10994eae5014STrond Myklebust static void put_nfs_open_context_sync(struct nfs_open_context *ctx)
11004eae5014STrond Myklebust {
11014eae5014STrond Myklebust 	__put_nfs_open_context(ctx, 1);
11024eae5014STrond Myklebust }
11034eae5014STrond Myklebust 
11041da177e4SLinus Torvalds /*
11051da177e4SLinus Torvalds  * Ensure that mmap has a recent RPC credential for use when writing out
11061da177e4SLinus Torvalds  * shared pages
11071da177e4SLinus Torvalds  */
nfs_inode_attach_open_context(struct nfs_open_context * ctx)1108c45ffdd2STrond Myklebust void nfs_inode_attach_open_context(struct nfs_open_context *ctx)
11091da177e4SLinus Torvalds {
11102b0143b5SDavid Howells 	struct inode *inode = d_inode(ctx->dentry);
11111da177e4SLinus Torvalds 	struct nfs_inode *nfsi = NFS_I(inode);
11121da177e4SLinus Torvalds 
11131da177e4SLinus Torvalds 	spin_lock(&inode->i_lock);
11141c341b77STrond Myklebust 	if (list_empty(&nfsi->open_files) &&
11153db63daaSNeilBrown 	    nfs_ooo_test(nfsi))
1116ac46b3d7STrond Myklebust 		nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA |
1117ac46b3d7STrond Myklebust 						     NFS_INO_REVAL_FORCED);
11180de43976STrond Myklebust 	list_add_tail_rcu(&ctx->list, &nfsi->open_files);
11191da177e4SLinus Torvalds 	spin_unlock(&inode->i_lock);
11201da177e4SLinus Torvalds }
1121c45ffdd2STrond Myklebust EXPORT_SYMBOL_GPL(nfs_inode_attach_open_context);
1122c45ffdd2STrond Myklebust 
nfs_file_set_open_context(struct file * filp,struct nfs_open_context * ctx)1123c45ffdd2STrond Myklebust void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
1124c45ffdd2STrond Myklebust {
1125c45ffdd2STrond Myklebust 	filp->private_data = get_nfs_open_context(ctx);
1126e97bc663STrond Myklebust 	set_bit(NFS_CONTEXT_FILE_OPEN, &ctx->flags);
1127c45ffdd2STrond Myklebust 	if (list_empty(&ctx->list))
1128c45ffdd2STrond Myklebust 		nfs_inode_attach_open_context(ctx);
1129c45ffdd2STrond Myklebust }
113089d77c8fSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_file_set_open_context);
11311da177e4SLinus Torvalds 
1132d530838bSTrond Myklebust /*
1133d530838bSTrond Myklebust  * Given an inode, search for an open context with the desired characteristics
1134d530838bSTrond Myklebust  */
nfs_find_open_context(struct inode * inode,const struct cred * cred,fmode_t mode)1135a52458b4SNeilBrown struct nfs_open_context *nfs_find_open_context(struct inode *inode, const struct cred *cred, fmode_t mode)
11361da177e4SLinus Torvalds {
11371da177e4SLinus Torvalds 	struct nfs_inode *nfsi = NFS_I(inode);
11381da177e4SLinus Torvalds 	struct nfs_open_context *pos, *ctx = NULL;
11391da177e4SLinus Torvalds 
11400de43976STrond Myklebust 	rcu_read_lock();
11410de43976STrond Myklebust 	list_for_each_entry_rcu(pos, &nfsi->open_files, list) {
114265f51603STrond Myklebust 		if (cred != NULL && cred_fscmp(pos->cred, cred) != 0)
1143d530838bSTrond Myklebust 			continue;
11441544fa0fSTrond Myklebust 		if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode)
11451544fa0fSTrond Myklebust 			continue;
1146e97bc663STrond Myklebust 		if (!test_bit(NFS_CONTEXT_FILE_OPEN, &pos->flags))
1147e97bc663STrond Myklebust 			continue;
11481da177e4SLinus Torvalds 		ctx = get_nfs_open_context(pos);
11490de43976STrond Myklebust 		if (ctx)
11501da177e4SLinus Torvalds 			break;
11511da177e4SLinus Torvalds 	}
11520de43976STrond Myklebust 	rcu_read_unlock();
11531da177e4SLinus Torvalds 	return ctx;
11541da177e4SLinus Torvalds }
11551da177e4SLinus Torvalds 
nfs_file_clear_open_context(struct file * filp)1156aff8d8dcSAnna Schumaker void nfs_file_clear_open_context(struct file *filp)
11571da177e4SLinus Torvalds {
1158cd3758e3STrond Myklebust 	struct nfs_open_context *ctx = nfs_file_open_context(filp);
11591da177e4SLinus Torvalds 
11601da177e4SLinus Torvalds 	if (ctx) {
11612b0143b5SDavid Howells 		struct inode *inode = d_inode(ctx->dentry);
1162c45ffdd2STrond Myklebust 
1163e97bc663STrond Myklebust 		clear_bit(NFS_CONTEXT_FILE_OPEN, &ctx->flags);
11640bcbf039SPeng Tao 		/*
11650bcbf039SPeng Tao 		 * We fatal error on write before. Try to writeback
11660bcbf039SPeng Tao 		 * every page again.
11670bcbf039SPeng Tao 		 */
11680bcbf039SPeng Tao 		if (ctx->error < 0)
11690bcbf039SPeng Tao 			invalidate_inode_pages2(inode->i_mapping);
11701da177e4SLinus Torvalds 		filp->private_data = NULL;
11714eae5014STrond Myklebust 		put_nfs_open_context_sync(ctx);
11721da177e4SLinus Torvalds 	}
11731da177e4SLinus Torvalds }
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds /*
11761da177e4SLinus Torvalds  * These allocate and release file read/write context information.
11771da177e4SLinus Torvalds  */
nfs_open(struct inode * inode,struct file * filp)11781da177e4SLinus Torvalds int nfs_open(struct inode *inode, struct file *filp)
11791da177e4SLinus Torvalds {
11801da177e4SLinus Torvalds 	struct nfs_open_context *ctx;
11811da177e4SLinus Torvalds 
11826f1c1d95SChenXiaoSong 	ctx = alloc_nfs_open_context(file_dentry(filp),
11836f1c1d95SChenXiaoSong 				     flags_to_mode(filp->f_flags), filp);
11845ede7b1cSAl Viro 	if (IS_ERR(ctx))
11855ede7b1cSAl Viro 		return PTR_ERR(ctx);
11861da177e4SLinus Torvalds 	nfs_file_set_open_context(filp, ctx);
11871da177e4SLinus Torvalds 	put_nfs_open_context(ctx);
1188f1fe29b4SDavid Howells 	nfs_fscache_open_file(inode, filp);
11891da177e4SLinus Torvalds 	return 0;
11901da177e4SLinus Torvalds }
11911da177e4SLinus Torvalds 
11921da177e4SLinus Torvalds /*
11931da177e4SLinus Torvalds  * This function is called whenever some part of NFS notices that
11941da177e4SLinus Torvalds  * the cached attributes have to be refreshed.
11951da177e4SLinus Torvalds  */
11961da177e4SLinus Torvalds int
__nfs_revalidate_inode(struct nfs_server * server,struct inode * inode)11971da177e4SLinus Torvalds __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
11981da177e4SLinus Torvalds {
11991da177e4SLinus Torvalds 	int		 status = -ESTALE;
1200a3cba2aaSTrond Myklebust 	struct nfs_fattr *fattr = NULL;
12011da177e4SLinus Torvalds 	struct nfs_inode *nfsi = NFS_I(inode);
12021da177e4SLinus Torvalds 
12031e8968c5SNiels de Vos 	dfprintk(PAGECACHE, "NFS: revalidating (%s/%Lu)\n",
12041e8968c5SNiels de Vos 		inode->i_sb->s_id, (unsigned long long)NFS_FILEID(inode));
12051da177e4SLinus Torvalds 
1206f4ce1299STrond Myklebust 	trace_nfs_revalidate_inode_enter(inode);
1207f4ce1299STrond Myklebust 
120885233a7aSChuck Lever 	if (is_bad_inode(inode))
1209412d582eSChuck Lever 		goto out;
12107fdc49c4STrond Myklebust 	if (NFS_STALE(inode))
1211412d582eSChuck Lever 		goto out;
12121da177e4SLinus Torvalds 
1213ac46bd37STrond Myklebust 	/* pNFS: Attributes aren't updated until we layoutcommit */
1214ac46bd37STrond Myklebust 	if (S_ISREG(inode->i_mode)) {
1215ac46bd37STrond Myklebust 		status = pnfs_sync_inode(inode, false);
1216ac46bd37STrond Myklebust 		if (status)
1217ac46bd37STrond Myklebust 			goto out;
1218ac46bd37STrond Myklebust 	}
1219ac46bd37STrond Myklebust 
1220a3cba2aaSTrond Myklebust 	status = -ENOMEM;
12212ef61e0eSAnna Schumaker 	fattr = nfs_alloc_fattr_with_label(NFS_SERVER(inode));
1222a3cba2aaSTrond Myklebust 	if (fattr == NULL)
1223a3cba2aaSTrond Myklebust 		goto out;
1224a3cba2aaSTrond Myklebust 
1225691beb13STrond Myklebust 	nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
122614c43f76SDavid Quigley 
12272ef61e0eSAnna Schumaker 	status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, inode);
12281da177e4SLinus Torvalds 	if (status != 0) {
12291e8968c5SNiels de Vos 		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) getattr failed, error=%d\n",
12301da177e4SLinus Torvalds 			 inode->i_sb->s_id,
12311e8968c5SNiels de Vos 			 (unsigned long long)NFS_FILEID(inode), status);
1232c74dfe97STrond Myklebust 		switch (status) {
1233c74dfe97STrond Myklebust 		case -ETIMEDOUT:
1234c74dfe97STrond Myklebust 			/* A soft timeout occurred. Use cached information? */
1235c74dfe97STrond Myklebust 			if (server->flags & NFS_MOUNT_SOFTREVAL)
1236c74dfe97STrond Myklebust 				status = 0;
1237c74dfe97STrond Myklebust 			break;
1238c74dfe97STrond Myklebust 		case -ESTALE:
12391da177e4SLinus Torvalds 			if (!S_ISDIR(inode->i_mode))
124093ce4af7STrond Myklebust 				nfs_set_inode_stale(inode);
124193ce4af7STrond Myklebust 			else
124293ce4af7STrond Myklebust 				nfs_zap_caches(inode);
12431da177e4SLinus Torvalds 		}
12442ef61e0eSAnna Schumaker 		goto out;
12451da177e4SLinus Torvalds 	}
12461da177e4SLinus Torvalds 
1247a3cba2aaSTrond Myklebust 	status = nfs_refresh_inode(inode, fattr);
12481da177e4SLinus Torvalds 	if (status) {
12491e8968c5SNiels de Vos 		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) refresh failed, error=%d\n",
12501da177e4SLinus Torvalds 			 inode->i_sb->s_id,
12511e8968c5SNiels de Vos 			 (unsigned long long)NFS_FILEID(inode), status);
12522ef61e0eSAnna Schumaker 		goto out;
12531da177e4SLinus Torvalds 	}
125455296809SChuck Lever 
125524aa1fe6STrond Myklebust 	if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
1256ada70d94STrond Myklebust 		nfs_zap_acl_cache(inode);
125755296809SChuck Lever 
1258dd225cb3SAnna Schumaker 	nfs_setsecurity(inode, fattr);
12593da580aaSJeff Layton 
12601e8968c5SNiels de Vos 	dfprintk(PAGECACHE, "NFS: (%s/%Lu) revalidation complete\n",
12611da177e4SLinus Torvalds 		inode->i_sb->s_id,
12621e8968c5SNiels de Vos 		(unsigned long long)NFS_FILEID(inode));
12631da177e4SLinus Torvalds 
12641da177e4SLinus Torvalds out:
1265a3cba2aaSTrond Myklebust 	nfs_free_fattr(fattr);
1266f4ce1299STrond Myklebust 	trace_nfs_revalidate_inode_exit(inode, status);
12671da177e4SLinus Torvalds 	return status;
12681da177e4SLinus Torvalds }
12691da177e4SLinus Torvalds 
nfs_attribute_cache_expired(struct inode * inode)127043f291cdSScott Mayhew int nfs_attribute_cache_expired(struct inode *inode)
1271d7cf8dd0STrond Myklebust {
1272b4d2314bSTrond Myklebust 	if (nfs_have_delegated_attributes(inode))
12731da177e4SLinus Torvalds 		return 0;
1274d7cf8dd0STrond Myklebust 	return nfs_attribute_timeout(inode);
12751da177e4SLinus Torvalds }
12761da177e4SLinus Torvalds 
12771da177e4SLinus Torvalds /**
12781da177e4SLinus Torvalds  * nfs_revalidate_inode - Revalidate the inode attributes
1279302fad7bSTrond Myklebust  * @inode: pointer to inode struct
12801f3208b2STrond Myklebust  * @flags: cache flags to check
12811da177e4SLinus Torvalds  *
12821da177e4SLinus Torvalds  * Updates inode attribute information by retrieving the data from the server.
12831da177e4SLinus Torvalds  */
nfs_revalidate_inode(struct inode * inode,unsigned long flags)12841f3208b2STrond Myklebust int nfs_revalidate_inode(struct inode *inode, unsigned long flags)
12851da177e4SLinus Torvalds {
12861f3208b2STrond Myklebust 	if (!nfs_check_cache_invalid(inode, flags))
12871da177e4SLinus Torvalds 		return NFS_STALE(inode) ? -ESTALE : 0;
12881f3208b2STrond Myklebust 	return __nfs_revalidate_inode(NFS_SERVER(inode), inode);
12891da177e4SLinus Torvalds }
12901c606fb7SBryan Schumaker EXPORT_SYMBOL_GPL(nfs_revalidate_inode);
12911da177e4SLinus Torvalds 
nfs_invalidate_mapping(struct inode * inode,struct address_space * mapping)12921cda707dSTrond Myklebust static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
12937d52e862STrond Myklebust {
1294f8806c84STrond Myklebust 	int ret;
129544b11874STrond Myklebust 
1296a6b5a28eSDave Wysochanski 	nfs_fscache_invalidate(inode, 0);
1297cd9ae2b6STrond Myklebust 	if (mapping->nrpages != 0) {
1298f8806c84STrond Myklebust 		if (S_ISREG(inode->i_mode)) {
1299f8806c84STrond Myklebust 			ret = nfs_sync_mapping(mapping);
1300f8806c84STrond Myklebust 			if (ret < 0)
1301f8806c84STrond Myklebust 				return ret;
1302f8806c84STrond Myklebust 		}
1303f8806c84STrond Myklebust 		ret = invalidate_inode_pages2(mapping);
1304cd9ae2b6STrond Myklebust 		if (ret < 0)
1305717d44e8STrond Myklebust 			return ret;
1306cd9ae2b6STrond Myklebust 	}
1307cd9ae2b6STrond Myklebust 	nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
1308f4ce1299STrond Myklebust 
13091e8968c5SNiels de Vos 	dfprintk(PAGECACHE, "NFS: (%s/%Lu) data cache invalidated\n",
13101e8968c5SNiels de Vos 			inode->i_sb->s_id,
13111e8968c5SNiels de Vos 			(unsigned long long)NFS_FILEID(inode));
1312717d44e8STrond Myklebust 	return 0;
13137d52e862STrond Myklebust }
1314717d44e8STrond Myklebust 
131528aa2f9eSTrond Myklebust /**
131628aa2f9eSTrond Myklebust  * nfs_clear_invalid_mapping - Conditionally clear a mapping
131728aa2f9eSTrond Myklebust  * @mapping: pointer to mapping
131828aa2f9eSTrond Myklebust  *
131928aa2f9eSTrond Myklebust  * If the NFS_INO_INVALID_DATA inode flag is set, clear the mapping.
132028aa2f9eSTrond Myklebust  */
nfs_clear_invalid_mapping(struct address_space * mapping)132128aa2f9eSTrond Myklebust int nfs_clear_invalid_mapping(struct address_space *mapping)
132228aa2f9eSTrond Myklebust {
132328aa2f9eSTrond Myklebust 	struct inode *inode = mapping->host;
132428aa2f9eSTrond Myklebust 	struct nfs_inode *nfsi = NFS_I(inode);
132528aa2f9eSTrond Myklebust 	unsigned long *bitlock = &nfsi->flags;
132628aa2f9eSTrond Myklebust 	int ret = 0;
132728aa2f9eSTrond Myklebust 
132828aa2f9eSTrond Myklebust 	/*
132928aa2f9eSTrond Myklebust 	 * We must clear NFS_INO_INVALID_DATA first to ensure that
133028aa2f9eSTrond Myklebust 	 * invalidations that come in while we're shooting down the mappings
133128aa2f9eSTrond Myklebust 	 * are respected. But, that leaves a race window where one revalidator
133228aa2f9eSTrond Myklebust 	 * can clear the flag, and then another checks it before the mapping
133328aa2f9eSTrond Myklebust 	 * gets invalidated. Fix that by serializing access to this part of
133428aa2f9eSTrond Myklebust 	 * the function.
133528aa2f9eSTrond Myklebust 	 *
133628aa2f9eSTrond Myklebust 	 * At the same time, we need to allow other tasks to see whether we
133728aa2f9eSTrond Myklebust 	 * might be in the middle of invalidating the pages, so we only set
133828aa2f9eSTrond Myklebust 	 * the bit lock here if it looks like we're going to be doing that.
133928aa2f9eSTrond Myklebust 	 */
134028aa2f9eSTrond Myklebust 	for (;;) {
134128aa2f9eSTrond Myklebust 		ret = wait_on_bit_action(bitlock, NFS_INO_INVALIDATING,
1342f5d39b02SPeter Zijlstra 					 nfs_wait_bit_killable,
1343f5d39b02SPeter Zijlstra 					 TASK_KILLABLE|TASK_FREEZABLE_UNSAFE);
134428aa2f9eSTrond Myklebust 		if (ret)
134528aa2f9eSTrond Myklebust 			goto out;
13466173b0bfSMike Snitzer 		smp_rmb(); /* pairs with smp_wmb() below */
13476173b0bfSMike Snitzer 		if (test_bit(NFS_INO_INVALIDATING, bitlock))
13486173b0bfSMike Snitzer 			continue;
13496173b0bfSMike Snitzer 		/* pairs with nfs_set_cache_invalid()'s smp_store_release() */
13506173b0bfSMike Snitzer 		if (!(smp_load_acquire(&nfsi->cache_validity) & NFS_INO_INVALID_DATA))
13516173b0bfSMike Snitzer 			goto out;
13526173b0bfSMike Snitzer 		/* Slow-path that double-checks with spinlock held */
135328aa2f9eSTrond Myklebust 		spin_lock(&inode->i_lock);
135428aa2f9eSTrond Myklebust 		if (test_bit(NFS_INO_INVALIDATING, bitlock)) {
135528aa2f9eSTrond Myklebust 			spin_unlock(&inode->i_lock);
135628aa2f9eSTrond Myklebust 			continue;
135728aa2f9eSTrond Myklebust 		}
135828aa2f9eSTrond Myklebust 		if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
135928aa2f9eSTrond Myklebust 			break;
136028aa2f9eSTrond Myklebust 		spin_unlock(&inode->i_lock);
136128aa2f9eSTrond Myklebust 		goto out;
136228aa2f9eSTrond Myklebust 	}
136328aa2f9eSTrond Myklebust 
136428aa2f9eSTrond Myklebust 	set_bit(NFS_INO_INVALIDATING, bitlock);
136528aa2f9eSTrond Myklebust 	smp_wmb();
13663db63daaSNeilBrown 	nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
13673db63daaSNeilBrown 	nfs_ooo_clear(nfsi);
136828aa2f9eSTrond Myklebust 	spin_unlock(&inode->i_lock);
136928aa2f9eSTrond Myklebust 	trace_nfs_invalidate_mapping_enter(inode);
137028aa2f9eSTrond Myklebust 	ret = nfs_invalidate_mapping(inode, mapping);
137128aa2f9eSTrond Myklebust 	trace_nfs_invalidate_mapping_exit(inode, ret);
137228aa2f9eSTrond Myklebust 
137328aa2f9eSTrond Myklebust 	clear_bit_unlock(NFS_INO_INVALIDATING, bitlock);
137428aa2f9eSTrond Myklebust 	smp_mb__after_atomic();
137528aa2f9eSTrond Myklebust 	wake_up_bit(bitlock, NFS_INO_INVALIDATING);
137628aa2f9eSTrond Myklebust out:
137728aa2f9eSTrond Myklebust 	return ret;
137828aa2f9eSTrond Myklebust }
137928aa2f9eSTrond Myklebust 
nfs_mapping_need_revalidate_inode(struct inode * inode)13801cd9cb05STrond Myklebust bool nfs_mapping_need_revalidate_inode(struct inode *inode)
1381b4b1eadfSTrond Myklebust {
138213c0b082STrond Myklebust 	return nfs_check_cache_invalid(inode, NFS_INO_INVALID_CHANGE) ||
138361540bf6STrond Myklebust 		NFS_STALE(inode);
1384b4b1eadfSTrond Myklebust }
1385b4b1eadfSTrond Myklebust 
nfs_revalidate_mapping_rcu(struct inode * inode)13860d0def49SAl Viro int nfs_revalidate_mapping_rcu(struct inode *inode)
13870d0def49SAl Viro {
13880d0def49SAl Viro 	struct nfs_inode *nfsi = NFS_I(inode);
13890d0def49SAl Viro 	unsigned long *bitlock = &nfsi->flags;
13900d0def49SAl Viro 	int ret = 0;
13910d0def49SAl Viro 
13920d0def49SAl Viro 	if (IS_SWAPFILE(inode))
13930d0def49SAl Viro 		goto out;
13940d0def49SAl Viro 	if (nfs_mapping_need_revalidate_inode(inode)) {
13950d0def49SAl Viro 		ret = -ECHILD;
13960d0def49SAl Viro 		goto out;
13970d0def49SAl Viro 	}
13980d0def49SAl Viro 	spin_lock(&inode->i_lock);
13990d0def49SAl Viro 	if (test_bit(NFS_INO_INVALIDATING, bitlock) ||
14000d0def49SAl Viro 	    (nfsi->cache_validity & NFS_INO_INVALID_DATA))
14010d0def49SAl Viro 		ret = -ECHILD;
14020d0def49SAl Viro 	spin_unlock(&inode->i_lock);
14030d0def49SAl Viro out:
14040d0def49SAl Viro 	return ret;
14050d0def49SAl Viro }
14060d0def49SAl Viro 
1407717d44e8STrond Myklebust /**
1408be527494STrond Myklebust  * nfs_revalidate_mapping - Revalidate the pagecache
1409302fad7bSTrond Myklebust  * @inode: pointer to host inode
1410302fad7bSTrond Myklebust  * @mapping: pointer to mapping
1411717d44e8STrond Myklebust  */
nfs_revalidate_mapping(struct inode * inode,struct address_space * mapping)141228aa2f9eSTrond Myklebust int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
1413717d44e8STrond Myklebust {
141429418aa4SMel Gorman 	/* swapfiles are not supposed to be shared. */
141529418aa4SMel Gorman 	if (IS_SWAPFILE(inode))
141628aa2f9eSTrond Myklebust 		return 0;
141729418aa4SMel Gorman 
1418b4b1eadfSTrond Myklebust 	if (nfs_mapping_need_revalidate_inode(inode)) {
141928aa2f9eSTrond Myklebust 		int ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
1420717d44e8STrond Myklebust 		if (ret < 0)
142144b11874STrond Myklebust 			return ret;
14227d52e862STrond Myklebust 	}
14237d52e862STrond Myklebust 
142428aa2f9eSTrond Myklebust 	return nfs_clear_invalid_mapping(mapping);
142528aa2f9eSTrond Myklebust }
142628aa2f9eSTrond Myklebust 
nfs_file_has_writers(struct nfs_inode * nfsi)1427ca0daa27STrond Myklebust static bool nfs_file_has_writers(struct nfs_inode *nfsi)
1428874f9463STrond Myklebust {
1429ca0daa27STrond Myklebust 	struct inode *inode = &nfsi->vfs_inode;
1430ca0daa27STrond Myklebust 
1431ca0daa27STrond Myklebust 	if (!S_ISREG(inode->i_mode))
1432ca0daa27STrond Myklebust 		return false;
1433ca0daa27STrond Myklebust 	if (list_empty(&nfsi->open_files))
1434ca0daa27STrond Myklebust 		return false;
14356ba0c4e5STrond Myklebust 	return inode_is_open_for_write(inode);
1436874f9463STrond Myklebust }
1437874f9463STrond Myklebust 
nfs_file_has_buffered_writers(struct nfs_inode * nfsi)1438651b0e70STrond Myklebust static bool nfs_file_has_buffered_writers(struct nfs_inode *nfsi)
1439874f9463STrond Myklebust {
1440651b0e70STrond Myklebust 	return nfs_file_has_writers(nfsi) && nfs_file_io_is_buffered(nfsi);
1441874f9463STrond Myklebust }
1442874f9463STrond Myklebust 
nfs_wcc_update_inode(struct inode * inode,struct nfs_fattr * fattr)1443783b194cSTrond Myklebust static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1444a895b4a1STrond Myklebust {
1445e86d5a02STrond Myklebust 	struct timespec64 ts;
144695582b00SDeepa Dinamani 
14479e6e70f8STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
14489e6e70f8STrond Myklebust 			&& (fattr->valid & NFS_ATTR_FATTR_CHANGE)
1449c472c07bSGoffredo Baroncelli 			&& inode_eq_iversion_raw(inode, fattr->pre_change_attr)) {
14501eb5d98fSJeff Layton 		inode_set_iversion_raw(inode, fattr->change_attr);
145170ca8852STrond Myklebust 		if (S_ISDIR(inode->i_mode))
14526edf9609STrond Myklebust 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA);
14530f44da51SFrank van der Linden 		else if (nfs_server_capable(inode, NFS_CAP_XATTR))
14540f44da51SFrank van der Linden 			nfs_set_cache_invalid(inode, NFS_INO_INVALID_XATTR);
145570ca8852STrond Myklebust 	}
1456a895b4a1STrond Myklebust 	/* If we have atomic WCC data, we may update some attributes */
145755e04e9cSJeff Layton 	ts = inode_get_ctime(inode);
14589e6e70f8STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME)
14599e6e70f8STrond Myklebust 			&& (fattr->valid & NFS_ATTR_FATTR_CTIME)
1460e86d5a02STrond Myklebust 			&& timespec64_equal(&ts, &fattr->pre_ctime)) {
146155e04e9cSJeff Layton 		inode_set_ctime_to_ts(inode, fattr->ctime);
146227dc1cd3STrond Myklebust 	}
14639e6e70f8STrond Myklebust 
1464e86d5a02STrond Myklebust 	ts = inode->i_mtime;
14659e6e70f8STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME)
14669e6e70f8STrond Myklebust 			&& (fattr->valid & NFS_ATTR_FATTR_MTIME)
1467e86d5a02STrond Myklebust 			&& timespec64_equal(&ts, &fattr->pre_mtime)) {
1468e86d5a02STrond Myklebust 		inode->i_mtime = fattr->mtime;
1469a895b4a1STrond Myklebust 	}
14709e6e70f8STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
14719e6e70f8STrond Myklebust 			&& (fattr->valid & NFS_ATTR_FATTR_SIZE)
14729e6e70f8STrond Myklebust 			&& i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
1473a6b6d5b8STrond Myklebust 			&& !nfs_have_writebacks(inode)) {
1474110cb2d2SChuck Lever 		trace_nfs_size_wcc(inode, fattr->size);
1475a3d01454STrond Myklebust 		i_size_write(inode, nfs_size_to_loff_t(fattr->size));
147627dc1cd3STrond Myklebust 	}
1477a895b4a1STrond Myklebust }
1478a895b4a1STrond Myklebust 
14791da177e4SLinus Torvalds /**
148033801147STrond Myklebust  * nfs_check_inode_attributes - verify consistency of the inode attribute cache
1481302fad7bSTrond Myklebust  * @inode: pointer to inode
1482302fad7bSTrond Myklebust  * @fattr: updated attributes
14831da177e4SLinus Torvalds  *
14841da177e4SLinus Torvalds  * Verifies the attribute cache. If we have just changed the attributes,
14851da177e4SLinus Torvalds  * so that fattr carries weak cache consistency data, then it may
14861da177e4SLinus Torvalds  * also update the ctime/mtime/change_attribute.
14871da177e4SLinus Torvalds  */
nfs_check_inode_attributes(struct inode * inode,struct nfs_fattr * fattr)148833801147STrond Myklebust static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fattr)
14891da177e4SLinus Torvalds {
14901da177e4SLinus Torvalds 	struct nfs_inode *nfsi = NFS_I(inode);
14911da177e4SLinus Torvalds 	loff_t cur_size, new_isize;
14922a3f5fd4STrond Myklebust 	unsigned long invalid = 0;
1493e86d5a02STrond Myklebust 	struct timespec64 ts;
1494dc59250cSChuck Lever 
14954ebe83afSTrond Myklebust 	if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ))
149601da47bdSTrond Myklebust 		return 0;
14974ebe83afSTrond Myklebust 
1498eb3d8f42STrond Myklebust 	if (!(fattr->valid & NFS_ATTR_FATTR_FILEID)) {
1499eb3d8f42STrond Myklebust 		/* Only a mounted-on-fileid? Just exit */
1500eb3d8f42STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
15017e10cc25STrond Myklebust 			return 0;
15021da177e4SLinus Torvalds 	/* Has the inode gone and changed behind our back? */
1503eb3d8f42STrond Myklebust 	} else if (nfsi->fileid != fattr->fileid) {
15047e10cc25STrond Myklebust 		/* Is this perhaps the mounted-on fileid? */
15057e10cc25STrond Myklebust 		if ((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) &&
15067e10cc25STrond Myklebust 		    nfsi->fileid == fattr->mounted_on_fileid)
15077e10cc25STrond Myklebust 			return 0;
1508cc89684cSNeilBrown 		return -ESTALE;
15097e10cc25STrond Myklebust 	}
15106e3e2c43SAl Viro 	if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && inode_wrong_type(inode, fattr->mode))
1511cc89684cSNeilBrown 		return -ESTALE;
15121da177e4SLinus Torvalds 
15137e10cc25STrond Myklebust 
1514651b0e70STrond Myklebust 	if (!nfs_file_has_buffered_writers(nfsi)) {
1515ca0daa27STrond Myklebust 		/* Verify a few of the more important attributes */
1516c472c07bSGoffredo Baroncelli 		if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && !inode_eq_iversion_raw(inode, fattr->change_attr))
151704c63498STrond Myklebust 			invalid |= NFS_INO_INVALID_CHANGE;
15181da177e4SLinus Torvalds 
1519e86d5a02STrond Myklebust 		ts = inode->i_mtime;
1520e86d5a02STrond Myklebust 		if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec64_equal(&ts, &fattr->mtime))
152116e14375STrond Myklebust 			invalid |= NFS_INO_INVALID_MTIME;
1522ca62b9c3STrond Myklebust 
152355e04e9cSJeff Layton 		ts = inode_get_ctime(inode);
1524e86d5a02STrond Myklebust 		if ((fattr->valid & NFS_ATTR_FATTR_CTIME) && !timespec64_equal(&ts, &fattr->ctime))
152516e14375STrond Myklebust 			invalid |= NFS_INO_INVALID_CTIME;
1526ca0daa27STrond Myklebust 
15279e6e70f8STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
1528ca62b9c3STrond Myklebust 			cur_size = i_size_read(inode);
1529ca62b9c3STrond Myklebust 			new_isize = nfs_size_to_loff_t(fattr->size);
153085a23ceeSTrond Myklebust 			if (cur_size != new_isize)
153104c63498STrond Myklebust 				invalid |= NFS_INO_INVALID_SIZE;
15329e6e70f8STrond Myklebust 		}
1533ca0daa27STrond Myklebust 	}
15341da177e4SLinus Torvalds 
15351da177e4SLinus Torvalds 	/* Have any file permissions changed? */
15369e6e70f8STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
153704c63498STrond Myklebust 		invalid |= NFS_INO_INVALID_MODE;
15389ff593c4SEric W. Biederman 	if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && !uid_eq(inode->i_uid, fattr->uid))
153904c63498STrond Myklebust 		invalid |= NFS_INO_INVALID_OTHER;
15409ff593c4SEric W. Biederman 	if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && !gid_eq(inode->i_gid, fattr->gid))
154104c63498STrond Myklebust 		invalid |= NFS_INO_INVALID_OTHER;
15421da177e4SLinus Torvalds 
15431da177e4SLinus Torvalds 	/* Has the link count changed? */
15449e6e70f8STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR_NLINK) && inode->i_nlink != fattr->nlink)
1545fabf2b34STrond Myklebust 		invalid |= NFS_INO_INVALID_NLINK;
15461da177e4SLinus Torvalds 
1547e86d5a02STrond Myklebust 	ts = inode->i_atime;
1548e86d5a02STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR_ATIME) && !timespec64_equal(&ts, &fattr->atime))
15492a3f5fd4STrond Myklebust 		invalid |= NFS_INO_INVALID_ATIME;
15502a3f5fd4STrond Myklebust 
15512a3f5fd4STrond Myklebust 	if (invalid != 0)
15524ebe83afSTrond Myklebust 		nfs_set_cache_invalid(inode, invalid);
15531da177e4SLinus Torvalds 
155433801147STrond Myklebust 	nfsi->read_cache_jiffies = fattr->time_start;
15551da177e4SLinus Torvalds 	return 0;
15561da177e4SLinus Torvalds }
15571da177e4SLinus Torvalds 
1558ae05f269STrond Myklebust static atomic_long_t nfs_attr_generation_counter;
15594704f0e2STrond Myklebust 
nfs_read_attr_generation_counter(void)15604704f0e2STrond Myklebust static unsigned long nfs_read_attr_generation_counter(void)
15614704f0e2STrond Myklebust {
1562ae05f269STrond Myklebust 	return atomic_long_read(&nfs_attr_generation_counter);
15634704f0e2STrond Myklebust }
15644704f0e2STrond Myklebust 
nfs_inc_attr_generation_counter(void)15654704f0e2STrond Myklebust unsigned long nfs_inc_attr_generation_counter(void)
15664704f0e2STrond Myklebust {
1567ae05f269STrond Myklebust 	return atomic_long_inc_return(&nfs_attr_generation_counter);
15684704f0e2STrond Myklebust }
15693235b403STrond Myklebust EXPORT_SYMBOL_GPL(nfs_inc_attr_generation_counter);
15704704f0e2STrond Myklebust 
nfs_fattr_init(struct nfs_fattr * fattr)15714704f0e2STrond Myklebust void nfs_fattr_init(struct nfs_fattr *fattr)
15724704f0e2STrond Myklebust {
15734704f0e2STrond Myklebust 	fattr->valid = 0;
15744704f0e2STrond Myklebust 	fattr->time_start = jiffies;
15754704f0e2STrond Myklebust 	fattr->gencount = nfs_inc_attr_generation_counter();
15766926afd1STrond Myklebust 	fattr->owner_name = NULL;
15776926afd1STrond Myklebust 	fattr->group_name = NULL;
1578*f749cb60SRoberto Sassu 	fattr->mdsthreshold = NULL;
15794704f0e2STrond Myklebust }
1580ddda8e0aSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_fattr_init);
15814704f0e2STrond Myklebust 
1582140e049cSTrond Myklebust /**
1583140e049cSTrond Myklebust  * nfs_fattr_set_barrier
1584140e049cSTrond Myklebust  * @fattr: attributes
1585140e049cSTrond Myklebust  *
1586140e049cSTrond Myklebust  * Used to set a barrier after an attribute was updated. This
1587140e049cSTrond Myklebust  * barrier ensures that older attributes from RPC calls that may
1588140e049cSTrond Myklebust  * have raced with our update cannot clobber these new values.
1589140e049cSTrond Myklebust  * Note that you are still responsible for ensuring that other
1590140e049cSTrond Myklebust  * operations which change the attribute on the server do not
1591140e049cSTrond Myklebust  * collide.
1592140e049cSTrond Myklebust  */
nfs_fattr_set_barrier(struct nfs_fattr * fattr)1593140e049cSTrond Myklebust void nfs_fattr_set_barrier(struct nfs_fattr *fattr)
1594140e049cSTrond Myklebust {
1595140e049cSTrond Myklebust 	fattr->gencount = nfs_inc_attr_generation_counter();
1596140e049cSTrond Myklebust }
1597140e049cSTrond Myklebust 
nfs_alloc_fattr(void)15982d36bfdeSTrond Myklebust struct nfs_fattr *nfs_alloc_fattr(void)
15992d36bfdeSTrond Myklebust {
16002d36bfdeSTrond Myklebust 	struct nfs_fattr *fattr;
16012d36bfdeSTrond Myklebust 
1602da48f267STrond Myklebust 	fattr = kmalloc(sizeof(*fattr), GFP_KERNEL);
1603d4a95a7eSTrond Myklebust 	if (fattr != NULL) {
16042d36bfdeSTrond Myklebust 		nfs_fattr_init(fattr);
1605d4a95a7eSTrond Myklebust 		fattr->label = NULL;
1606d4a95a7eSTrond Myklebust 	}
16072d36bfdeSTrond Myklebust 	return fattr;
16082d36bfdeSTrond Myklebust }
1609ddda8e0aSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_alloc_fattr);
16102d36bfdeSTrond Myklebust 
nfs_alloc_fattr_with_label(struct nfs_server * server)1611d755ad8dSAnna Schumaker struct nfs_fattr *nfs_alloc_fattr_with_label(struct nfs_server *server)
1612d755ad8dSAnna Schumaker {
1613d755ad8dSAnna Schumaker 	struct nfs_fattr *fattr = nfs_alloc_fattr();
1614d755ad8dSAnna Schumaker 
1615d755ad8dSAnna Schumaker 	if (!fattr)
1616d755ad8dSAnna Schumaker 		return NULL;
1617d755ad8dSAnna Schumaker 
1618da48f267STrond Myklebust 	fattr->label = nfs4_label_alloc(server, GFP_KERNEL);
1619d755ad8dSAnna Schumaker 	if (IS_ERR(fattr->label)) {
1620d755ad8dSAnna Schumaker 		kfree(fattr);
1621d755ad8dSAnna Schumaker 		return NULL;
1622d755ad8dSAnna Schumaker 	}
1623d755ad8dSAnna Schumaker 
1624d755ad8dSAnna Schumaker 	return fattr;
1625d755ad8dSAnna Schumaker }
1626d755ad8dSAnna Schumaker EXPORT_SYMBOL_GPL(nfs_alloc_fattr_with_label);
1627d755ad8dSAnna Schumaker 
nfs_alloc_fhandle(void)16282d36bfdeSTrond Myklebust struct nfs_fh *nfs_alloc_fhandle(void)
16292d36bfdeSTrond Myklebust {
16302d36bfdeSTrond Myklebust 	struct nfs_fh *fh;
16312d36bfdeSTrond Myklebust 
1632da48f267STrond Myklebust 	fh = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
16332d36bfdeSTrond Myklebust 	if (fh != NULL)
16342d36bfdeSTrond Myklebust 		fh->size = 0;
16352d36bfdeSTrond Myklebust 	return fh;
16362d36bfdeSTrond Myklebust }
1637ddda8e0aSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_alloc_fhandle);
16382d36bfdeSTrond Myklebust 
1639e27d359eSTrond Myklebust #ifdef NFS_DEBUG
1640d8e0539eSWeston Andros Adamson /*
1641d8e0539eSWeston Andros Adamson  * _nfs_display_fhandle_hash - calculate the crc32 hash for the filehandle
1642d8e0539eSWeston Andros Adamson  *                             in the same way that wireshark does
1643d8e0539eSWeston Andros Adamson  *
1644d8e0539eSWeston Andros Adamson  * @fh: file handle
1645d8e0539eSWeston Andros Adamson  *
1646d8e0539eSWeston Andros Adamson  * For debugging only.
1647d8e0539eSWeston Andros Adamson  */
_nfs_display_fhandle_hash(const struct nfs_fh * fh)1648d8e0539eSWeston Andros Adamson u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh)
1649d8e0539eSWeston Andros Adamson {
1650d8e0539eSWeston Andros Adamson 	/* wireshark uses 32-bit AUTODIN crc and does a bitwise
1651d8e0539eSWeston Andros Adamson 	 * not on the result */
16521264a2f0STrond Myklebust 	return nfs_fhandle_hash(fh);
1653d8e0539eSWeston Andros Adamson }
16549e6ee76dSChuck Lever EXPORT_SYMBOL_GPL(_nfs_display_fhandle_hash);
1655d8e0539eSWeston Andros Adamson 
1656d8e0539eSWeston Andros Adamson /*
165720d27e92SChuck Lever  * _nfs_display_fhandle - display an NFS file handle on the console
165820d27e92SChuck Lever  *
165920d27e92SChuck Lever  * @fh: file handle to display
166020d27e92SChuck Lever  * @caption: display caption
166120d27e92SChuck Lever  *
166220d27e92SChuck Lever  * For debugging only.
166320d27e92SChuck Lever  */
_nfs_display_fhandle(const struct nfs_fh * fh,const char * caption)166420d27e92SChuck Lever void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption)
166520d27e92SChuck Lever {
166620d27e92SChuck Lever 	unsigned short i;
166720d27e92SChuck Lever 
1668fa68a1baSTrond Myklebust 	if (fh == NULL || fh->size == 0) {
166920d27e92SChuck Lever 		printk(KERN_DEFAULT "%s at %p is empty\n", caption, fh);
167020d27e92SChuck Lever 		return;
167120d27e92SChuck Lever 	}
167220d27e92SChuck Lever 
1673d8e0539eSWeston Andros Adamson 	printk(KERN_DEFAULT "%s at %p is %u bytes, crc: 0x%08x:\n",
1674d8e0539eSWeston Andros Adamson 	       caption, fh, fh->size, _nfs_display_fhandle_hash(fh));
167520d27e92SChuck Lever 	for (i = 0; i < fh->size; i += 16) {
167620d27e92SChuck Lever 		__be32 *pos = (__be32 *)&fh->data[i];
167720d27e92SChuck Lever 
167820d27e92SChuck Lever 		switch ((fh->size - i - 1) >> 2) {
167920d27e92SChuck Lever 		case 0:
168020d27e92SChuck Lever 			printk(KERN_DEFAULT " %08x\n",
168120d27e92SChuck Lever 				be32_to_cpup(pos));
168220d27e92SChuck Lever 			break;
168320d27e92SChuck Lever 		case 1:
168420d27e92SChuck Lever 			printk(KERN_DEFAULT " %08x %08x\n",
168520d27e92SChuck Lever 				be32_to_cpup(pos), be32_to_cpup(pos + 1));
168620d27e92SChuck Lever 			break;
168720d27e92SChuck Lever 		case 2:
168820d27e92SChuck Lever 			printk(KERN_DEFAULT " %08x %08x %08x\n",
168920d27e92SChuck Lever 				be32_to_cpup(pos), be32_to_cpup(pos + 1),
169020d27e92SChuck Lever 				be32_to_cpup(pos + 2));
169120d27e92SChuck Lever 			break;
169220d27e92SChuck Lever 		default:
169320d27e92SChuck Lever 			printk(KERN_DEFAULT " %08x %08x %08x %08x\n",
169420d27e92SChuck Lever 				be32_to_cpup(pos), be32_to_cpup(pos + 1),
169520d27e92SChuck Lever 				be32_to_cpup(pos + 2), be32_to_cpup(pos + 3));
169620d27e92SChuck Lever 		}
169720d27e92SChuck Lever 	}
169820d27e92SChuck Lever }
16999e6ee76dSChuck Lever EXPORT_SYMBOL_GPL(_nfs_display_fhandle);
170020d27e92SChuck Lever #endif
170120d27e92SChuck Lever 
170220d27e92SChuck Lever /**
17036f9be83dSTrond Myklebust  * nfs_inode_attrs_cmp_generic - compare attributes
1704302fad7bSTrond Myklebust  * @fattr: attributes
17056f9be83dSTrond Myklebust  * @inode: pointer to inode
1706a10ad176STrond Myklebust  *
1707a10ad176STrond Myklebust  * Attempt to divine whether or not an RPC call reply carrying stale
1708a10ad176STrond Myklebust  * attributes got scheduled after another call carrying updated ones.
17094704f0e2STrond Myklebust  * Note also the check for wraparound of 'attr_gencount'
1710a10ad176STrond Myklebust  *
17116f9be83dSTrond Myklebust  * The function returns '1' if it thinks the attributes in @fattr are
17126f9be83dSTrond Myklebust  * more recent than the ones cached in @inode. Otherwise it returns
17136f9be83dSTrond Myklebust  * the value '0'.
1714a10ad176STrond Myklebust  */
nfs_inode_attrs_cmp_generic(const struct nfs_fattr * fattr,const struct inode * inode)17156f9be83dSTrond Myklebust static int nfs_inode_attrs_cmp_generic(const struct nfs_fattr *fattr,
17166f9be83dSTrond Myklebust 				       const struct inode *inode)
1717a10ad176STrond Myklebust {
17189fdbfad1STrond Myklebust 	unsigned long attr_gencount = NFS_I(inode)->attr_gencount;
1719a10ad176STrond Myklebust 
17209fdbfad1STrond Myklebust 	return (long)(fattr->gencount - attr_gencount) > 0 ||
17219fdbfad1STrond Myklebust 	       (long)(attr_gencount - nfs_read_attr_generation_counter()) > 0;
1722a10ad176STrond Myklebust }
1723a10ad176STrond Myklebust 
17246f9be83dSTrond Myklebust /**
17256f9be83dSTrond Myklebust  * nfs_inode_attrs_cmp_monotonic - compare attributes
17266f9be83dSTrond Myklebust  * @fattr: attributes
17276f9be83dSTrond Myklebust  * @inode: pointer to inode
172833801147STrond Myklebust  *
172933801147STrond Myklebust  * Attempt to divine whether or not an RPC call reply carrying stale
173033801147STrond Myklebust  * attributes got scheduled after another call carrying updated ones.
173133801147STrond Myklebust  *
17326f9be83dSTrond Myklebust  * We assume that the server observes monotonic semantics for
17336f9be83dSTrond Myklebust  * the change attribute, so a larger value means that the attributes in
17346f9be83dSTrond Myklebust  * @fattr are more recent, in which case the function returns the
17356f9be83dSTrond Myklebust  * value '1'.
17366f9be83dSTrond Myklebust  * A return value of '0' indicates no measurable change
17376f9be83dSTrond Myklebust  * A return value of '-1' means that the attributes in @inode are
17386f9be83dSTrond Myklebust  * more recent.
173933801147STrond Myklebust  */
nfs_inode_attrs_cmp_monotonic(const struct nfs_fattr * fattr,const struct inode * inode)17406f9be83dSTrond Myklebust static int nfs_inode_attrs_cmp_monotonic(const struct nfs_fattr *fattr,
17416f9be83dSTrond Myklebust 					 const struct inode *inode)
174233801147STrond Myklebust {
17436f9be83dSTrond Myklebust 	s64 diff = fattr->change_attr - inode_peek_iversion_raw(inode);
17446f9be83dSTrond Myklebust 	if (diff > 0)
17456f9be83dSTrond Myklebust 		return 1;
17466f9be83dSTrond Myklebust 	return diff == 0 ? 0 : -1;
1747f551e44fSChuck Lever }
1748f551e44fSChuck Lever 
17496f9be83dSTrond Myklebust /**
17506f9be83dSTrond Myklebust  * nfs_inode_attrs_cmp_strict_monotonic - compare attributes
17516f9be83dSTrond Myklebust  * @fattr: attributes
17526f9be83dSTrond Myklebust  * @inode: pointer to inode
17536f9be83dSTrond Myklebust  *
17546f9be83dSTrond Myklebust  * Attempt to divine whether or not an RPC call reply carrying stale
17556f9be83dSTrond Myklebust  * attributes got scheduled after another call carrying updated ones.
17566f9be83dSTrond Myklebust  *
17576f9be83dSTrond Myklebust  * We assume that the server observes strictly monotonic semantics for
17586f9be83dSTrond Myklebust  * the change attribute, so a larger value means that the attributes in
17596f9be83dSTrond Myklebust  * @fattr are more recent, in which case the function returns the
17606f9be83dSTrond Myklebust  * value '1'.
17616f9be83dSTrond Myklebust  * A return value of '-1' means that the attributes in @inode are
17626f9be83dSTrond Myklebust  * more recent or unchanged.
17636f9be83dSTrond Myklebust  */
nfs_inode_attrs_cmp_strict_monotonic(const struct nfs_fattr * fattr,const struct inode * inode)17646f9be83dSTrond Myklebust static int nfs_inode_attrs_cmp_strict_monotonic(const struct nfs_fattr *fattr,
17656f9be83dSTrond Myklebust 						const struct inode *inode)
1766f551e44fSChuck Lever {
17676f9be83dSTrond Myklebust 	return  nfs_inode_attrs_cmp_monotonic(fattr, inode) > 0 ? 1 : -1;
17686f9be83dSTrond Myklebust }
17696f9be83dSTrond Myklebust 
17706f9be83dSTrond Myklebust /**
17716f9be83dSTrond Myklebust  * nfs_inode_attrs_cmp - compare attributes
17726f9be83dSTrond Myklebust  * @fattr: attributes
17736f9be83dSTrond Myklebust  * @inode: pointer to inode
17746f9be83dSTrond Myklebust  *
17756f9be83dSTrond Myklebust  * This function returns '1' if it thinks the attributes in @fattr are
17766f9be83dSTrond Myklebust  * more recent than the ones cached in @inode. It returns '-1' if
17776f9be83dSTrond Myklebust  * the attributes in @inode are more recent than the ones in @fattr,
17786f9be83dSTrond Myklebust  * and it returns 0 if not sure.
17796f9be83dSTrond Myklebust  */
nfs_inode_attrs_cmp(const struct nfs_fattr * fattr,const struct inode * inode)17806f9be83dSTrond Myklebust static int nfs_inode_attrs_cmp(const struct nfs_fattr *fattr,
17816f9be83dSTrond Myklebust 			       const struct inode *inode)
17826f9be83dSTrond Myklebust {
17836f9be83dSTrond Myklebust 	if (nfs_inode_attrs_cmp_generic(fattr, inode) > 0)
17846f9be83dSTrond Myklebust 		return 1;
17856f9be83dSTrond Myklebust 	switch (NFS_SERVER(inode)->change_attr_type) {
17866f9be83dSTrond Myklebust 	case NFS4_CHANGE_TYPE_IS_UNDEFINED:
17876f9be83dSTrond Myklebust 		break;
17886f9be83dSTrond Myklebust 	case NFS4_CHANGE_TYPE_IS_TIME_METADATA:
17896f9be83dSTrond Myklebust 		if (!(fattr->valid & NFS_ATTR_FATTR_CHANGE))
17906f9be83dSTrond Myklebust 			break;
17916f9be83dSTrond Myklebust 		return nfs_inode_attrs_cmp_monotonic(fattr, inode);
17926f9be83dSTrond Myklebust 	default:
17936f9be83dSTrond Myklebust 		if (!(fattr->valid & NFS_ATTR_FATTR_CHANGE))
17946f9be83dSTrond Myklebust 			break;
17956f9be83dSTrond Myklebust 		return nfs_inode_attrs_cmp_strict_monotonic(fattr, inode);
17966f9be83dSTrond Myklebust 	}
17976f9be83dSTrond Myklebust 	return 0;
17986f9be83dSTrond Myklebust }
17996f9be83dSTrond Myklebust 
18007b24dacfSTrond Myklebust /**
18017b24dacfSTrond Myklebust  * nfs_inode_finish_partial_attr_update - complete a previous inode update
18027b24dacfSTrond Myklebust  * @fattr: attributes
18037b24dacfSTrond Myklebust  * @inode: pointer to inode
18047b24dacfSTrond Myklebust  *
18057b24dacfSTrond Myklebust  * Returns '1' if the last attribute update left the inode cached
18067b24dacfSTrond Myklebust  * attributes in a partially unrevalidated state, and @fattr
18077b24dacfSTrond Myklebust  * matches the change attribute of that partial update.
18087b24dacfSTrond Myklebust  * Otherwise returns '0'.
18097b24dacfSTrond Myklebust  */
nfs_inode_finish_partial_attr_update(const struct nfs_fattr * fattr,const struct inode * inode)18107b24dacfSTrond Myklebust static int nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr,
18117b24dacfSTrond Myklebust 						const struct inode *inode)
18127b24dacfSTrond Myklebust {
18137b24dacfSTrond Myklebust 	const unsigned long check_valid =
18147b24dacfSTrond Myklebust 		NFS_INO_INVALID_ATIME | NFS_INO_INVALID_CTIME |
18157b24dacfSTrond Myklebust 		NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
18167b24dacfSTrond Myklebust 		NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER |
18177b24dacfSTrond Myklebust 		NFS_INO_INVALID_NLINK;
18187b24dacfSTrond Myklebust 	unsigned long cache_validity = NFS_I(inode)->cache_validity;
1819eea41330STrond Myklebust 	enum nfs4_change_attr_type ctype = NFS_SERVER(inode)->change_attr_type;
18207b24dacfSTrond Myklebust 
1821eea41330STrond Myklebust 	if (ctype != NFS4_CHANGE_TYPE_IS_UNDEFINED &&
1822eea41330STrond Myklebust 	    !(cache_validity & NFS_INO_INVALID_CHANGE) &&
18237b24dacfSTrond Myklebust 	    (cache_validity & check_valid) != 0 &&
18247b24dacfSTrond Myklebust 	    (fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
18257b24dacfSTrond Myklebust 	    nfs_inode_attrs_cmp_monotonic(fattr, inode) == 0)
18267b24dacfSTrond Myklebust 		return 1;
18277b24dacfSTrond Myklebust 	return 0;
18287b24dacfSTrond Myklebust }
18297b24dacfSTrond Myklebust 
nfs_ooo_merge(struct nfs_inode * nfsi,u64 start,u64 end)18303db63daaSNeilBrown static void nfs_ooo_merge(struct nfs_inode *nfsi,
18313db63daaSNeilBrown 			  u64 start, u64 end)
18323db63daaSNeilBrown {
18333db63daaSNeilBrown 	int i, cnt;
18343db63daaSNeilBrown 
18353db63daaSNeilBrown 	if (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER)
18363db63daaSNeilBrown 		/* No point merging anything */
18373db63daaSNeilBrown 		return;
18383db63daaSNeilBrown 
18393db63daaSNeilBrown 	if (!nfsi->ooo) {
18403db63daaSNeilBrown 		nfsi->ooo = kmalloc(sizeof(*nfsi->ooo), GFP_ATOMIC);
18413db63daaSNeilBrown 		if (!nfsi->ooo) {
18423db63daaSNeilBrown 			nfsi->cache_validity |= NFS_INO_DATA_INVAL_DEFER;
18433db63daaSNeilBrown 			return;
18443db63daaSNeilBrown 		}
18453db63daaSNeilBrown 		nfsi->ooo->cnt = 0;
18463db63daaSNeilBrown 	}
18473db63daaSNeilBrown 
18483db63daaSNeilBrown 	/* add this range, merging if possible */
18493db63daaSNeilBrown 	cnt = nfsi->ooo->cnt;
18503db63daaSNeilBrown 	for (i = 0; i < cnt; i++) {
18513db63daaSNeilBrown 		if (end == nfsi->ooo->gap[i].start)
18523db63daaSNeilBrown 			end = nfsi->ooo->gap[i].end;
18533db63daaSNeilBrown 		else if (start == nfsi->ooo->gap[i].end)
18543db63daaSNeilBrown 			start = nfsi->ooo->gap[i].start;
18553db63daaSNeilBrown 		else
18563db63daaSNeilBrown 			continue;
18573db63daaSNeilBrown 		/* Remove 'i' from table and loop to insert the new range */
18583db63daaSNeilBrown 		cnt -= 1;
18593db63daaSNeilBrown 		nfsi->ooo->gap[i] = nfsi->ooo->gap[cnt];
18603db63daaSNeilBrown 		i = -1;
18613db63daaSNeilBrown 	}
18623db63daaSNeilBrown 	if (start != end) {
18633db63daaSNeilBrown 		if (cnt >= ARRAY_SIZE(nfsi->ooo->gap)) {
18643db63daaSNeilBrown 			nfsi->cache_validity |= NFS_INO_DATA_INVAL_DEFER;
18653db63daaSNeilBrown 			kfree(nfsi->ooo);
18663db63daaSNeilBrown 			nfsi->ooo = NULL;
18673db63daaSNeilBrown 			return;
18683db63daaSNeilBrown 		}
18693db63daaSNeilBrown 		nfsi->ooo->gap[cnt].start = start;
18703db63daaSNeilBrown 		nfsi->ooo->gap[cnt].end = end;
18713db63daaSNeilBrown 		cnt += 1;
18723db63daaSNeilBrown 	}
18733db63daaSNeilBrown 	nfsi->ooo->cnt = cnt;
18743db63daaSNeilBrown }
18753db63daaSNeilBrown 
nfs_ooo_record(struct nfs_inode * nfsi,struct nfs_fattr * fattr)18763db63daaSNeilBrown static void nfs_ooo_record(struct nfs_inode *nfsi,
18773db63daaSNeilBrown 			   struct nfs_fattr *fattr)
18783db63daaSNeilBrown {
18793db63daaSNeilBrown 	/* This reply was out-of-order, so record in the
18803db63daaSNeilBrown 	 * pre/post change id, possibly cancelling
18813db63daaSNeilBrown 	 * gaps created when iversion was jumpped forward.
18823db63daaSNeilBrown 	 */
18833db63daaSNeilBrown 	if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) &&
18843db63daaSNeilBrown 	    (fattr->valid & NFS_ATTR_FATTR_PRECHANGE))
18853db63daaSNeilBrown 		nfs_ooo_merge(nfsi,
18863db63daaSNeilBrown 			      fattr->change_attr,
18873db63daaSNeilBrown 			      fattr->pre_change_attr);
18883db63daaSNeilBrown }
18893db63daaSNeilBrown 
nfs_refresh_inode_locked(struct inode * inode,struct nfs_fattr * fattr)18906f9be83dSTrond Myklebust static int nfs_refresh_inode_locked(struct inode *inode,
18916f9be83dSTrond Myklebust 				    struct nfs_fattr *fattr)
18926f9be83dSTrond Myklebust {
18936f9be83dSTrond Myklebust 	int attr_cmp = nfs_inode_attrs_cmp(fattr, inode);
18946f9be83dSTrond Myklebust 	int ret = 0;
1895f4ce1299STrond Myklebust 
1896f4ce1299STrond Myklebust 	trace_nfs_refresh_inode_enter(inode);
1897f4ce1299STrond Myklebust 
18987b24dacfSTrond Myklebust 	if (attr_cmp > 0 || nfs_inode_finish_partial_attr_update(fattr, inode))
1899f4ce1299STrond Myklebust 		ret = nfs_update_inode(inode, fattr);
19003db63daaSNeilBrown 	else {
19013db63daaSNeilBrown 		nfs_ooo_record(NFS_I(inode), fattr);
19023db63daaSNeilBrown 
19033db63daaSNeilBrown 		if (attr_cmp == 0)
1904f4ce1299STrond Myklebust 			ret = nfs_check_inode_attributes(inode, fattr);
19053db63daaSNeilBrown 	}
1906f4ce1299STrond Myklebust 
1907f4ce1299STrond Myklebust 	trace_nfs_refresh_inode_exit(inode, ret);
1908f4ce1299STrond Myklebust 	return ret;
190933801147STrond Myklebust }
191033801147STrond Myklebust 
191133801147STrond Myklebust /**
191233801147STrond Myklebust  * nfs_refresh_inode - try to update the inode attribute cache
1913302fad7bSTrond Myklebust  * @inode: pointer to inode
1914302fad7bSTrond Myklebust  * @fattr: updated attributes
191533801147STrond Myklebust  *
191633801147STrond Myklebust  * Check that an RPC call that returned attributes has not overlapped with
191733801147STrond Myklebust  * other recent updates of the inode metadata, then decide whether it is
191833801147STrond Myklebust  * safe to do a full update of the inode attributes, or whether just to
191933801147STrond Myklebust  * call nfs_check_inode_attributes.
192033801147STrond Myklebust  */
nfs_refresh_inode(struct inode * inode,struct nfs_fattr * fattr)192133801147STrond Myklebust int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
192233801147STrond Myklebust {
192333801147STrond Myklebust 	int status;
192433801147STrond Myklebust 
192524aa1fe6STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
192633801147STrond Myklebust 		return 0;
192733801147STrond Myklebust 	spin_lock(&inode->i_lock);
192833801147STrond Myklebust 	status = nfs_refresh_inode_locked(inode, fattr);
192933801147STrond Myklebust 	spin_unlock(&inode->i_lock);
1930ef79c097SDavid Howells 
193133801147STrond Myklebust 	return status;
193233801147STrond Myklebust }
1933ddda8e0aSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_refresh_inode);
193433801147STrond Myklebust 
nfs_post_op_update_inode_locked(struct inode * inode,struct nfs_fattr * fattr,unsigned int invalid)193516e14375STrond Myklebust static int nfs_post_op_update_inode_locked(struct inode *inode,
193616e14375STrond Myklebust 		struct nfs_fattr *fattr, unsigned int invalid)
1937d65f557fSTrond Myklebust {
19386edf9609STrond Myklebust 	if (S_ISDIR(inode->i_mode))
19396edf9609STrond Myklebust 		invalid |= NFS_INO_INVALID_DATA;
19406edf9609STrond Myklebust 	nfs_set_cache_invalid(inode, invalid);
1941d65f557fSTrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
1942d65f557fSTrond Myklebust 		return 0;
1943d65f557fSTrond Myklebust 	return nfs_refresh_inode_locked(inode, fattr);
1944d65f557fSTrond Myklebust }
1945d65f557fSTrond Myklebust 
1946decf491fSTrond Myklebust /**
1947decf491fSTrond Myklebust  * nfs_post_op_update_inode - try to update the inode attribute cache
1948302fad7bSTrond Myklebust  * @inode: pointer to inode
1949302fad7bSTrond Myklebust  * @fattr: updated attributes
1950decf491fSTrond Myklebust  *
1951decf491fSTrond Myklebust  * After an operation that has changed the inode metadata, mark the
1952decf491fSTrond Myklebust  * attribute cache as being invalid, then try to update it.
1953f551e44fSChuck Lever  *
1954f551e44fSChuck Lever  * NB: if the server didn't return any post op attributes, this
1955f551e44fSChuck Lever  * function will force the retrieval of attributes before the next
1956f551e44fSChuck Lever  * NFS request.  Thus it should be used only for operations that
1957f551e44fSChuck Lever  * are expected to change one or more attributes, to avoid
1958f551e44fSChuck Lever  * unnecessary NFS requests and trips through nfs_update_inode().
1959decf491fSTrond Myklebust  */
nfs_post_op_update_inode(struct inode * inode,struct nfs_fattr * fattr)1960decf491fSTrond Myklebust int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1961decf491fSTrond Myklebust {
1962d65f557fSTrond Myklebust 	int status;
1963decf491fSTrond Myklebust 
196440d24704STrond Myklebust 	spin_lock(&inode->i_lock);
196592d64e47STrond Myklebust 	nfs_fattr_set_barrier(fattr);
196616e14375STrond Myklebust 	status = nfs_post_op_update_inode_locked(inode, fattr,
196716e14375STrond Myklebust 			NFS_INO_INVALID_CHANGE
1968d554168fSTrond Myklebust 			| NFS_INO_INVALID_CTIME
1969d554168fSTrond Myklebust 			| NFS_INO_REVAL_FORCED);
197068e8a70dSTrond Myklebust 	spin_unlock(&inode->i_lock);
1971aa9c2669SDavid Quigley 
1972870a5be8STrond Myklebust 	return status;
1973decf491fSTrond Myklebust }
19741c606fb7SBryan Schumaker EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);
1975decf491fSTrond Myklebust 
197670ca8852STrond Myklebust /**
1977a08a8cd3STrond Myklebust  * nfs_post_op_update_inode_force_wcc_locked - update the inode attribute cache
1978302fad7bSTrond Myklebust  * @inode: pointer to inode
1979302fad7bSTrond Myklebust  * @fattr: updated attributes
198070ca8852STrond Myklebust  *
198170ca8852STrond Myklebust  * After an operation that has changed the inode metadata, mark the
198270ca8852STrond Myklebust  * attribute cache as being invalid, then try to update it. Fake up
198370ca8852STrond Myklebust  * weak cache consistency data, if none exist.
198470ca8852STrond Myklebust  *
198570ca8852STrond Myklebust  * This function is mainly designed to be used by the ->write_done() functions.
198670ca8852STrond Myklebust  */
nfs_post_op_update_inode_force_wcc_locked(struct inode * inode,struct nfs_fattr * fattr)1987a08a8cd3STrond Myklebust int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr)
198870ca8852STrond Myklebust {
19896f9be83dSTrond Myklebust 	int attr_cmp = nfs_inode_attrs_cmp(fattr, inode);
1990d65f557fSTrond Myklebust 	int status;
1991d65f557fSTrond Myklebust 
1992d65f557fSTrond Myklebust 	/* Don't do a WCC update if these attributes are already stale */
19936f9be83dSTrond Myklebust 	if (attr_cmp < 0)
19946f9be83dSTrond Myklebust 		return 0;
19956f9be83dSTrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR) == 0 || !attr_cmp) {
19963db63daaSNeilBrown 		/* Record the pre/post change info before clearing PRECHANGE */
19973db63daaSNeilBrown 		nfs_ooo_record(NFS_I(inode), fattr);
19989e6e70f8STrond Myklebust 		fattr->valid &= ~(NFS_ATTR_FATTR_PRECHANGE
19999e6e70f8STrond Myklebust 				| NFS_ATTR_FATTR_PRESIZE
20009e6e70f8STrond Myklebust 				| NFS_ATTR_FATTR_PREMTIME
20019e6e70f8STrond Myklebust 				| NFS_ATTR_FATTR_PRECTIME);
2002d65f557fSTrond Myklebust 		goto out_noforce;
2003d65f557fSTrond Myklebust 	}
20049e6e70f8STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
20059e6e70f8STrond Myklebust 			(fattr->valid & NFS_ATTR_FATTR_PRECHANGE) == 0) {
20061eb5d98fSJeff Layton 		fattr->pre_change_attr = inode_peek_iversion_raw(inode);
20079e6e70f8STrond Myklebust 		fattr->valid |= NFS_ATTR_FATTR_PRECHANGE;
200870ca8852STrond Myklebust 	}
20099e6e70f8STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR_CTIME) != 0 &&
20109e6e70f8STrond Myklebust 			(fattr->valid & NFS_ATTR_FATTR_PRECTIME) == 0) {
201155e04e9cSJeff Layton 		fattr->pre_ctime = inode_get_ctime(inode);
20129e6e70f8STrond Myklebust 		fattr->valid |= NFS_ATTR_FATTR_PRECTIME;
20139e6e70f8STrond Myklebust 	}
20149e6e70f8STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR_MTIME) != 0 &&
20159e6e70f8STrond Myklebust 			(fattr->valid & NFS_ATTR_FATTR_PREMTIME) == 0) {
2016e86d5a02STrond Myklebust 		fattr->pre_mtime = inode->i_mtime;
20179e6e70f8STrond Myklebust 		fattr->valid |= NFS_ATTR_FATTR_PREMTIME;
20189e6e70f8STrond Myklebust 	}
20199e6e70f8STrond Myklebust 	if ((fattr->valid & NFS_ATTR_FATTR_SIZE) != 0 &&
20209e6e70f8STrond Myklebust 			(fattr->valid & NFS_ATTR_FATTR_PRESIZE) == 0) {
2021a3d01454STrond Myklebust 		fattr->pre_size = i_size_read(inode);
20229e6e70f8STrond Myklebust 		fattr->valid |= NFS_ATTR_FATTR_PRESIZE;
202370ca8852STrond Myklebust 	}
2024d65f557fSTrond Myklebust out_noforce:
202516e14375STrond Myklebust 	status = nfs_post_op_update_inode_locked(inode, fattr,
202616e14375STrond Myklebust 			NFS_INO_INVALID_CHANGE
202716e14375STrond Myklebust 			| NFS_INO_INVALID_CTIME
20283a39e778SZheng Bin 			| NFS_INO_INVALID_MTIME
20293a39e778SZheng Bin 			| NFS_INO_INVALID_BLOCKS);
2030a08a8cd3STrond Myklebust 	return status;
2031a08a8cd3STrond Myklebust }
2032a08a8cd3STrond Myklebust 
2033a08a8cd3STrond Myklebust /**
2034a08a8cd3STrond Myklebust  * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache
2035302fad7bSTrond Myklebust  * @inode: pointer to inode
2036302fad7bSTrond Myklebust  * @fattr: updated attributes
2037a08a8cd3STrond Myklebust  *
2038a08a8cd3STrond Myklebust  * After an operation that has changed the inode metadata, mark the
2039a08a8cd3STrond Myklebust  * attribute cache as being invalid, then try to update it. Fake up
2040a08a8cd3STrond Myklebust  * weak cache consistency data, if none exist.
2041a08a8cd3STrond Myklebust  *
2042a08a8cd3STrond Myklebust  * This function is mainly designed to be used by the ->write_done() functions.
2043a08a8cd3STrond Myklebust  */
nfs_post_op_update_inode_force_wcc(struct inode * inode,struct nfs_fattr * fattr)2044a08a8cd3STrond Myklebust int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr)
2045a08a8cd3STrond Myklebust {
2046a08a8cd3STrond Myklebust 	int status;
2047a08a8cd3STrond Myklebust 
2048a08a8cd3STrond Myklebust 	spin_lock(&inode->i_lock);
20498f8ba1d7STrond Myklebust 	nfs_fattr_set_barrier(fattr);
2050a08a8cd3STrond Myklebust 	status = nfs_post_op_update_inode_force_wcc_locked(inode, fattr);
2051d65f557fSTrond Myklebust 	spin_unlock(&inode->i_lock);
2052d65f557fSTrond Myklebust 	return status;
205370ca8852STrond Myklebust }
2054ddda8e0aSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_post_op_update_inode_force_wcc);
205570ca8852STrond Myklebust 
2056ea96d1ecSAnna Schumaker 
20571da177e4SLinus Torvalds /*
20581da177e4SLinus Torvalds  * Many nfs protocol calls return the new file attributes after
20591da177e4SLinus Torvalds  * an operation.  Here we update the inode to reflect the state
20601da177e4SLinus Torvalds  * of the server's inode.
20611da177e4SLinus Torvalds  *
20621da177e4SLinus Torvalds  * This is a bit tricky because we have to make sure all dirty pages
20631da177e4SLinus Torvalds  * have been sent off to the server before calling invalidate_inode_pages.
20641da177e4SLinus Torvalds  * To make sure no other process adds more write requests while we try
20651da177e4SLinus Torvalds  * our best to flush them, we make them sleep during the attribute refresh.
20661da177e4SLinus Torvalds  *
20671da177e4SLinus Torvalds  * A very similar scenario holds for the dir cache.
20681da177e4SLinus Torvalds  */
nfs_update_inode(struct inode * inode,struct nfs_fattr * fattr)206924aa1fe6STrond Myklebust static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
20701da177e4SLinus Torvalds {
2071ce62b114STrond Myklebust 	struct nfs_server *server = NFS_SERVER(inode);
20721da177e4SLinus Torvalds 	struct nfs_inode *nfsi = NFS_I(inode);
2073951a143bSTrond Myklebust 	loff_t cur_isize, new_isize;
2074ce62b114STrond Myklebust 	u64 fattr_supported = server->fattr_valid;
20752a3f5fd4STrond Myklebust 	unsigned long invalid = 0;
20763e7d950aSTrond Myklebust 	unsigned long now = jiffies;
207762ab460cSTrond Myklebust 	unsigned long save_cache_validity;
2078651b0e70STrond Myklebust 	bool have_writers = nfs_file_has_buffered_writers(nfsi);
2079944171cbSBenjamin Coddington 	bool cache_revalidated = true;
20800b467264STrond Myklebust 	bool attr_changed = false;
2081c80d17c5STrond Myklebust 	bool have_delegation;
20821da177e4SLinus Torvalds 
20831e8968c5SNiels de Vos 	dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n",
20843110ff80SHarvey Harrison 			__func__, inode->i_sb->s_id, inode->i_ino,
20854f1abd22SWeston Andros Adamson 			nfs_display_fhandle_hash(NFS_FH(inode)),
20861da177e4SLinus Torvalds 			atomic_read(&inode->i_count), fattr->valid);
20871da177e4SLinus Torvalds 
2088eb3d8f42STrond Myklebust 	if (!(fattr->valid & NFS_ATTR_FATTR_FILEID)) {
2089eb3d8f42STrond Myklebust 		/* Only a mounted-on-fileid? Just exit */
2090eb3d8f42STrond Myklebust 		if (fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
20917e10cc25STrond Myklebust 			return 0;
20927e10cc25STrond Myklebust 	/* Has the inode gone and changed behind our back? */
2093eb3d8f42STrond Myklebust 	} else if (nfsi->fileid != fattr->fileid) {
20947e10cc25STrond Myklebust 		/* Is this perhaps the mounted-on fileid? */
20957e10cc25STrond Myklebust 		if ((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) &&
20967e10cc25STrond Myklebust 		    nfsi->fileid == fattr->mounted_on_fileid)
20977e10cc25STrond Myklebust 			return 0;
2098e73e6c9eSMatthew Treinish 		printk(KERN_ERR "NFS: server %s error: fileid changed\n"
2099e73e6c9eSMatthew Treinish 			"fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
2100e73e6c9eSMatthew Treinish 			NFS_SERVER(inode)->nfs_client->cl_hostname,
2101e73e6c9eSMatthew Treinish 			inode->i_sb->s_id, (long long)nfsi->fileid,
2102e73e6c9eSMatthew Treinish 			(long long)fattr->fileid);
2103e73e6c9eSMatthew Treinish 		goto out_err;
2104e73e6c9eSMatthew Treinish 	}
21051da177e4SLinus Torvalds 
21061da177e4SLinus Torvalds 	/*
21071da177e4SLinus Torvalds 	 * Make sure the inode's type hasn't changed.
21081da177e4SLinus Torvalds 	 */
21096e3e2c43SAl Viro 	if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && inode_wrong_type(inode, fattr->mode)) {
2110e73e6c9eSMatthew Treinish 		/*
2111e73e6c9eSMatthew Treinish 		* Big trouble! The inode has become a different object.
2112e73e6c9eSMatthew Treinish 		*/
21131e8968c5SNiels de Vos 		printk(KERN_DEBUG "NFS: %s: inode %lu mode changed, %07o to %07o\n",
2114e73e6c9eSMatthew Treinish 				__func__, inode->i_ino, inode->i_mode, fattr->mode);
2115e73e6c9eSMatthew Treinish 		goto out_err;
2116e73e6c9eSMatthew Treinish 	}
21171da177e4SLinus Torvalds 
2118a0356862STrond Myklebust 	/* Update the fsid? */
21199e6e70f8STrond Myklebust 	if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) &&
2120c37dcd33STrond Myklebust 			!nfs_fsid_equal(&server->fsid, &fattr->fsid) &&
212136d43a43SDavid Howells 			!IS_AUTOMOUNT(inode))
21228b4bdcf8STrond Myklebust 		server->fsid = fattr->fsid;
21238b4bdcf8STrond Myklebust 
2124c80d17c5STrond Myklebust 	/* Save the delegation state before clearing cache_validity */
2125c80d17c5STrond Myklebust 	have_delegation = nfs_have_delegated_attributes(inode);
2126c80d17c5STrond Myklebust 
21271da177e4SLinus Torvalds 	/*
21281da177e4SLinus Torvalds 	 * Update the read time so we don't revalidate too often.
21291da177e4SLinus Torvalds 	 */
213033801147STrond Myklebust 	nfsi->read_cache_jiffies = fattr->time_start;
21313e7d950aSTrond Myklebust 
213262ab460cSTrond Myklebust 	save_cache_validity = nfsi->cache_validity;
21339e6e70f8STrond Myklebust 	nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
21349e6e70f8STrond Myklebust 			| NFS_INO_INVALID_ATIME
213562ab460cSTrond Myklebust 			| NFS_INO_REVAL_FORCED
21363a39e778SZheng Bin 			| NFS_INO_INVALID_BLOCKS);
21371da177e4SLinus Torvalds 
2138a895b4a1STrond Myklebust 	/* Do atomic weak cache consistency updates */
2139783b194cSTrond Myklebust 	nfs_wcc_update_inode(inode, fattr);
2140a895b4a1STrond Myklebust 
2141944171cbSBenjamin Coddington 	if (pnfs_layoutcommit_outstanding(inode)) {
2142709fa576STrond Myklebust 		nfsi->cache_validity |=
2143709fa576STrond Myklebust 			save_cache_validity &
2144709fa576STrond Myklebust 			(NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME |
2145709fa576STrond Myklebust 			 NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE |
2146cc7f2daeSTrond Myklebust 			 NFS_INO_INVALID_BLOCKS);
2147944171cbSBenjamin Coddington 		cache_revalidated = false;
2148944171cbSBenjamin Coddington 	}
214910b7e9adSTrond Myklebust 
215047aabaa7STrond Myklebust 	/* More cache consistency checks */
21519e6e70f8STrond Myklebust 	if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
21523db63daaSNeilBrown 		if (!have_writers && nfsi->ooo && nfsi->ooo->cnt == 1 &&
21533db63daaSNeilBrown 		    nfsi->ooo->gap[0].end == inode_peek_iversion_raw(inode)) {
21543db63daaSNeilBrown 			/* There is one remaining gap that hasn't been
21553db63daaSNeilBrown 			 * merged into iversion - do that now.
21563db63daaSNeilBrown 			 */
21573db63daaSNeilBrown 			inode_set_iversion_raw(inode, nfsi->ooo->gap[0].start);
21583db63daaSNeilBrown 			kfree(nfsi->ooo);
21593db63daaSNeilBrown 			nfsi->ooo = NULL;
21603db63daaSNeilBrown 		}
2161c472c07bSGoffredo Baroncelli 		if (!inode_eq_iversion_raw(inode, fattr->change_attr)) {
216238512aa9STrond Myklebust 			/* Could it be a race with writeback? */
2163c80d17c5STrond Myklebust 			if (!(have_writers || have_delegation)) {
21640b467264STrond Myklebust 				invalid |= NFS_INO_INVALID_DATA
21656a4506c0STrond Myklebust 					| NFS_INO_INVALID_ACCESS
216695ad37f9SFrank van der Linden 					| NFS_INO_INVALID_ACL
216795ad37f9SFrank van der Linden 					| NFS_INO_INVALID_XATTR;
2168cac88f94STrond Myklebust 				/* Force revalidate of all attributes */
216916e14375STrond Myklebust 				save_cache_validity |= NFS_INO_INVALID_CTIME
217016e14375STrond Myklebust 					| NFS_INO_INVALID_MTIME
217116e14375STrond Myklebust 					| NFS_INO_INVALID_SIZE
21724cdfeb64STrond Myklebust 					| NFS_INO_INVALID_BLOCKS
2173fabf2b34STrond Myklebust 					| NFS_INO_INVALID_NLINK
2174720869ebSTrond Myklebust 					| NFS_INO_INVALID_MODE
217516e14375STrond Myklebust 					| NFS_INO_INVALID_OTHER;
21769e6e70f8STrond Myklebust 				if (S_ISDIR(inode->i_mode))
21779e6e70f8STrond Myklebust 					nfs_force_lookup_revalidate(inode);
2178a9601ac5STrond Myklebust 				attr_changed = true;
2179c80d17c5STrond Myklebust 				dprintk("NFS: change_attr change on server for file %s/%ld\n",
2180c80d17c5STrond Myklebust 						inode->i_sb->s_id,
2181c80d17c5STrond Myklebust 						inode->i_ino);
21823db63daaSNeilBrown 			} else if (!have_delegation) {
21833db63daaSNeilBrown 				nfs_ooo_record(nfsi, fattr);
21843db63daaSNeilBrown 				nfs_ooo_merge(nfsi, inode_peek_iversion_raw(inode),
21853db63daaSNeilBrown 					      fattr->change_attr);
21863db63daaSNeilBrown 			}
21871eb5d98fSJeff Layton 			inode_set_iversion_raw(inode, fattr->change_attr);
21889e6e70f8STrond Myklebust 		}
2189ade14a7dSTrond Myklebust 	} else {
2190cc7f2daeSTrond Myklebust 		nfsi->cache_validity |=
2191cc7f2daeSTrond Myklebust 			save_cache_validity & NFS_INO_INVALID_CHANGE;
2192213bb584STrond Myklebust 		if (!have_delegation ||
2193213bb584STrond Myklebust 		    (nfsi->cache_validity & NFS_INO_INVALID_CHANGE) != 0)
2194ade14a7dSTrond Myklebust 			cache_revalidated = false;
2195ade14a7dSTrond Myklebust 	}
21969e6e70f8STrond Myklebust 
2197213bb584STrond Myklebust 	if (fattr->valid & NFS_ATTR_FATTR_MTIME)
2198e86d5a02STrond Myklebust 		inode->i_mtime = fattr->mtime;
2199213bb584STrond Myklebust 	else if (fattr_supported & NFS_ATTR_FATTR_MTIME)
2200cc7f2daeSTrond Myklebust 		nfsi->cache_validity |=
2201cc7f2daeSTrond Myklebust 			save_cache_validity & NFS_INO_INVALID_MTIME;
220262ab460cSTrond Myklebust 
2203213bb584STrond Myklebust 	if (fattr->valid & NFS_ATTR_FATTR_CTIME)
220455e04e9cSJeff Layton 		inode_set_ctime_to_ts(inode, fattr->ctime);
2205213bb584STrond Myklebust 	else if (fattr_supported & NFS_ATTR_FATTR_CTIME)
2206cc7f2daeSTrond Myklebust 		nfsi->cache_validity |=
2207cc7f2daeSTrond Myklebust 			save_cache_validity & NFS_INO_INVALID_CTIME;
220847aabaa7STrond Myklebust 
2209951a143bSTrond Myklebust 	/* Check if our cached file size is stale */
22109e6e70f8STrond Myklebust 	if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
22111da177e4SLinus Torvalds 		new_isize = nfs_size_to_loff_t(fattr->size);
22121da177e4SLinus Torvalds 		cur_isize = i_size_read(inode);
2213c80d17c5STrond Myklebust 		if (new_isize != cur_isize && !have_delegation) {
2214b64e8a5eSTrond Myklebust 			/* Do we perhaps have any outstanding writes, or has
2215b64e8a5eSTrond Myklebust 			 * the file grown beyond our last write? */
2216a6b6d5b8STrond Myklebust 			if (!nfs_have_writebacks(inode) || new_isize > cur_isize) {
2217110cb2d2SChuck Lever 				trace_nfs_size_update(inode, new_isize);
2218a3d01454STrond Myklebust 				i_size_write(inode, new_isize);
2219ca0daa27STrond Myklebust 				if (!have_writers)
222016e14375STrond Myklebust 					invalid |= NFS_INO_INVALID_DATA;
22211da177e4SLinus Torvalds 			}
22221da177e4SLinus Torvalds 		}
22234cdfeb64STrond Myklebust 		if (new_isize == 0 &&
22244cdfeb64STrond Myklebust 		    !(fattr->valid & (NFS_ATTR_FATTR_SPACE_USED |
22254cdfeb64STrond Myklebust 				      NFS_ATTR_FATTR_BLOCKS_USED))) {
22264cdfeb64STrond Myklebust 			fattr->du.nfs3.used = 0;
22274cdfeb64STrond Myklebust 			fattr->valid |= NFS_ATTR_FATTR_SPACE_USED;
22284cdfeb64STrond Myklebust 		}
2229213bb584STrond Myklebust 	} else
2230cc7f2daeSTrond Myklebust 		nfsi->cache_validity |=
2231cc7f2daeSTrond Myklebust 			save_cache_validity & NFS_INO_INVALID_SIZE;
22321da177e4SLinus Torvalds 
22339e6e70f8STrond Myklebust 	if (fattr->valid & NFS_ATTR_FATTR_ATIME)
2234e86d5a02STrond Myklebust 		inode->i_atime = fattr->atime;
2235213bb584STrond Myklebust 	else if (fattr_supported & NFS_ATTR_FATTR_ATIME)
2236cc7f2daeSTrond Myklebust 		nfsi->cache_validity |=
2237cc7f2daeSTrond Myklebust 			save_cache_validity & NFS_INO_INVALID_ATIME;
22381da177e4SLinus Torvalds 
22399e6e70f8STrond Myklebust 	if (fattr->valid & NFS_ATTR_FATTR_MODE) {
22409e6e70f8STrond Myklebust 		if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
22419b4b3513STrond Myklebust 			umode_t newmode = inode->i_mode & S_IFMT;
22429b4b3513STrond Myklebust 			newmode |= fattr->mode & S_IALLUGO;
22439b4b3513STrond Myklebust 			inode->i_mode = newmode;
224416e14375STrond Myklebust 			invalid |= NFS_INO_INVALID_ACCESS
22450b467264STrond Myklebust 				| NFS_INO_INVALID_ACL;
22469e6e70f8STrond Myklebust 		}
2247213bb584STrond Myklebust 	} else if (fattr_supported & NFS_ATTR_FATTR_MODE)
2248cc7f2daeSTrond Myklebust 		nfsi->cache_validity |=
2249cc7f2daeSTrond Myklebust 			save_cache_validity & NFS_INO_INVALID_MODE;
225062ab460cSTrond Myklebust 
22519e6e70f8STrond Myklebust 	if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
22529ff593c4SEric W. Biederman 		if (!uid_eq(inode->i_uid, fattr->uid)) {
225316e14375STrond Myklebust 			invalid |= NFS_INO_INVALID_ACCESS
22540b467264STrond Myklebust 				| NFS_INO_INVALID_ACL;
22559e6e70f8STrond Myklebust 			inode->i_uid = fattr->uid;
22569e6e70f8STrond Myklebust 		}
2257213bb584STrond Myklebust 	} else if (fattr_supported & NFS_ATTR_FATTR_OWNER)
2258cc7f2daeSTrond Myklebust 		nfsi->cache_validity |=
2259cc7f2daeSTrond Myklebust 			save_cache_validity & NFS_INO_INVALID_OTHER;
226062ab460cSTrond Myklebust 
22619e6e70f8STrond Myklebust 	if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
22629ff593c4SEric W. Biederman 		if (!gid_eq(inode->i_gid, fattr->gid)) {
226316e14375STrond Myklebust 			invalid |= NFS_INO_INVALID_ACCESS
22640b467264STrond Myklebust 				| NFS_INO_INVALID_ACL;
22659e6e70f8STrond Myklebust 			inode->i_gid = fattr->gid;
22669e6e70f8STrond Myklebust 		}
2267213bb584STrond Myklebust 	} else if (fattr_supported & NFS_ATTR_FATTR_GROUP)
2268cc7f2daeSTrond Myklebust 		nfsi->cache_validity |=
2269cc7f2daeSTrond Myklebust 			save_cache_validity & NFS_INO_INVALID_OTHER;
22701da177e4SLinus Torvalds 
22719e6e70f8STrond Myklebust 	if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
227236a10a3cSTrond Myklebust 		if (inode->i_nlink != fattr->nlink)
2273bfe86848SMiklos Szeredi 			set_nlink(inode, fattr->nlink);
2274213bb584STrond Myklebust 	} else if (fattr_supported & NFS_ATTR_FATTR_NLINK)
2275cc7f2daeSTrond Myklebust 		nfsi->cache_validity |=
2276cc7f2daeSTrond Myklebust 			save_cache_validity & NFS_INO_INVALID_NLINK;
2277921615f1STrond Myklebust 
22789e6e70f8STrond Myklebust 	if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
22791da177e4SLinus Torvalds 		/*
22801da177e4SLinus Torvalds 		 * report the blocks in 512byte units
22811da177e4SLinus Torvalds 		 */
22821da177e4SLinus Torvalds 		inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
2283213bb584STrond Myklebust 	} else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED)
2284ce62b114STrond Myklebust 		nfsi->cache_validity |=
2285ce62b114STrond Myklebust 			save_cache_validity & NFS_INO_INVALID_BLOCKS;
2286ce62b114STrond Myklebust 
2287213bb584STrond Myklebust 	if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
22889e6e70f8STrond Myklebust 		inode->i_blocks = fattr->du.nfs2.blocks;
2289213bb584STrond Myklebust 	else if (fattr_supported & NFS_ATTR_FATTR_BLOCKS_USED)
2290cc7f2daeSTrond Myklebust 		nfsi->cache_validity |=
2291cc7f2daeSTrond Myklebust 			save_cache_validity & NFS_INO_INVALID_BLOCKS;
22921da177e4SLinus Torvalds 
22931da177e4SLinus Torvalds 	/* Update attrtimeo value if we're out of the unstable period */
22940b467264STrond Myklebust 	if (attr_changed) {
229591d5b470SChuck Lever 		nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
22961da177e4SLinus Torvalds 		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
22973e7d950aSTrond Myklebust 		nfsi->attrtimeo_timestamp = now;
2298f5062003STrond Myklebust 		/* Set barrier to be more recent than all outstanding updates */
22994704f0e2STrond Myklebust 		nfsi->attr_gencount = nfs_inc_attr_generation_counter();
23006d2b2966STrond Myklebust 	} else {
2301ade14a7dSTrond Myklebust 		if (cache_revalidated) {
2302ade14a7dSTrond Myklebust 			if (!time_in_range_open(now, nfsi->attrtimeo_timestamp,
2303ade14a7dSTrond Myklebust 				nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
2304ade14a7dSTrond Myklebust 				nfsi->attrtimeo <<= 1;
2305ade14a7dSTrond Myklebust 				if (nfsi->attrtimeo > NFS_MAXATTRTIMEO(inode))
23061da177e4SLinus Torvalds 					nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
2307ade14a7dSTrond Myklebust 			}
23083e7d950aSTrond Myklebust 			nfsi->attrtimeo_timestamp = now;
23091da177e4SLinus Torvalds 		}
2310f5062003STrond Myklebust 		/* Set the barrier to be more recent than this fattr */
23119fdbfad1STrond Myklebust 		if ((long)(fattr->gencount - nfsi->attr_gencount) > 0)
2312f5062003STrond Myklebust 			nfsi->attr_gencount = fattr->gencount;
23136d2b2966STrond Myklebust 	}
2314c812012fSJeff Layton 
23151da177e4SLinus Torvalds 	/* Don't invalidate the data if we were to blame */
23161da177e4SLinus Torvalds 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
23171da177e4SLinus Torvalds 				|| S_ISLNK(inode->i_mode)))
23181da177e4SLinus Torvalds 		invalid &= ~NFS_INO_INVALID_DATA;
23196edf9609STrond Myklebust 	nfs_set_cache_invalid(inode, invalid);
2320de242c0bSDavid Howells 
23211da177e4SLinus Torvalds 	return 0;
2322b37b03b7STrond Myklebust  out_err:
23231da177e4SLinus Torvalds 	/*
23241da177e4SLinus Torvalds 	 * No need to worry about unhashing the dentry, as the
23251da177e4SLinus Torvalds 	 * lookup validation will know that the inode is bad.
23261da177e4SLinus Torvalds 	 * (But we fall through to invalidate the caches.)
23271da177e4SLinus Torvalds 	 */
232893ce4af7STrond Myklebust 	nfs_set_inode_stale_locked(inode);
23291da177e4SLinus Torvalds 	return -ESTALE;
23301da177e4SLinus Torvalds }
23311da177e4SLinus Torvalds 
nfs_alloc_inode(struct super_block * sb)2332f7b422b1SDavid Howells struct inode *nfs_alloc_inode(struct super_block *sb)
23331da177e4SLinus Torvalds {
23341da177e4SLinus Torvalds 	struct nfs_inode *nfsi;
2335fd60b288SMuchun Song 	nfsi = alloc_inode_sb(sb, nfs_inode_cachep, GFP_KERNEL);
23361da177e4SLinus Torvalds 	if (!nfsi)
23371da177e4SLinus Torvalds 		return NULL;
233855296809SChuck Lever 	nfsi->flags = 0UL;
233955296809SChuck Lever 	nfsi->cache_validity = 0UL;
23403db63daaSNeilBrown 	nfsi->ooo = NULL;
234189d77c8fSBryan Schumaker #if IS_ENABLED(CONFIG_NFS_V4)
2342e50a1c2eSJ. Bruce Fields 	nfsi->nfs4_acl = NULL;
2343e50a1c2eSJ. Bruce Fields #endif /* CONFIG_NFS_V4 */
234495ad37f9SFrank van der Linden #ifdef CONFIG_NFS_V4_2
234595ad37f9SFrank van der Linden 	nfsi->xattr_cache = NULL;
234695ad37f9SFrank van der Linden #endif
2347000dbe0bSDave Wysochanski 	nfs_netfs_inode_init(nfsi);
2348000dbe0bSDave Wysochanski 
23491da177e4SLinus Torvalds 	return &nfsi->vfs_inode;
23501da177e4SLinus Torvalds }
235189d77c8fSBryan Schumaker EXPORT_SYMBOL_GPL(nfs_alloc_inode);
23521da177e4SLinus Torvalds 
nfs_free_inode(struct inode * inode)2353ca1a199eSAl Viro void nfs_free_inode(struct inode *inode)
2354fa0d7e3dSNick Piggin {
23553db63daaSNeilBrown 	kfree(NFS_I(inode)->ooo);
2356fa0d7e3dSNick Piggin 	kmem_cache_free(nfs_inode_cachep, NFS_I(inode));
2357fa0d7e3dSNick Piggin }
2358ca1a199eSAl Viro EXPORT_SYMBOL_GPL(nfs_free_inode);
23591da177e4SLinus Torvalds 
nfs4_init_once(struct nfs_inode * nfsi)2360d75d5414SAndrew Morton static inline void nfs4_init_once(struct nfs_inode *nfsi)
2361d75d5414SAndrew Morton {
236289d77c8fSBryan Schumaker #if IS_ENABLED(CONFIG_NFS_V4)
2363d75d5414SAndrew Morton 	INIT_LIST_HEAD(&nfsi->open_states);
2364d75d5414SAndrew Morton 	nfsi->delegation = NULL;
2365d75d5414SAndrew Morton 	init_rwsem(&nfsi->rwsem);
2366e5e94017SBenny Halevy 	nfsi->layout = NULL;
2367d75d5414SAndrew Morton #endif
2368d75d5414SAndrew Morton }
2369f7b422b1SDavid Howells 
init_once(void * foo)237051cc5068SAlexey Dobriyan static void init_once(void *foo)
23711da177e4SLinus Torvalds {
23727e7ce2ccSyuzhe 	struct nfs_inode *nfsi = foo;
23731da177e4SLinus Torvalds 
23741da177e4SLinus Torvalds 	inode_init_once(&nfsi->vfs_inode);
23751da177e4SLinus Torvalds 	INIT_LIST_HEAD(&nfsi->open_files);
2376cfcea3e8STrond Myklebust 	INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
2377cfcea3e8STrond Myklebust 	INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
23781da177e4SLinus Torvalds 	nfs4_init_once(nfsi);
23791da177e4SLinus Torvalds }
23801da177e4SLinus Torvalds 
nfs_init_inodecache(void)2381f7b422b1SDavid Howells static int __init nfs_init_inodecache(void)
23821da177e4SLinus Torvalds {
23831da177e4SLinus Torvalds 	nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
23841da177e4SLinus Torvalds 					     sizeof(struct nfs_inode),
2385fffb60f9SPaul Jackson 					     0, (SLAB_RECLAIM_ACCOUNT|
23865d097056SVladimir Davydov 						SLAB_MEM_SPREAD|SLAB_ACCOUNT),
238720c2df83SPaul Mundt 					     init_once);
23881da177e4SLinus Torvalds 	if (nfs_inode_cachep == NULL)
23891da177e4SLinus Torvalds 		return -ENOMEM;
23901da177e4SLinus Torvalds 
23911da177e4SLinus Torvalds 	return 0;
23921da177e4SLinus Torvalds }
23931da177e4SLinus Torvalds 
nfs_destroy_inodecache(void)2394266bee88SDavid Brownell static void nfs_destroy_inodecache(void)
23951da177e4SLinus Torvalds {
23968c0a8537SKirill A. Shutemov 	/*
23978c0a8537SKirill A. Shutemov 	 * Make sure all delayed rcu free inodes are flushed before we
23988c0a8537SKirill A. Shutemov 	 * destroy cache.
23998c0a8537SKirill A. Shutemov 	 */
24008c0a8537SKirill A. Shutemov 	rcu_barrier();
24011a1d92c1SAlexey Dobriyan 	kmem_cache_destroy(nfs_inode_cachep);
24021da177e4SLinus Torvalds }
24031da177e4SLinus Torvalds 
24045746006fSTrond Myklebust struct workqueue_struct *nfsiod_workqueue;
240589d77c8fSBryan Schumaker EXPORT_SYMBOL_GPL(nfsiod_workqueue);
24065746006fSTrond Myklebust 
24075746006fSTrond Myklebust /*
24085746006fSTrond Myklebust  * start up the nfsiod workqueue
24095746006fSTrond Myklebust  */
nfsiod_start(void)24105746006fSTrond Myklebust static int nfsiod_start(void)
24115746006fSTrond Myklebust {
24125746006fSTrond Myklebust 	struct workqueue_struct *wq;
24135746006fSTrond Myklebust 	dprintk("RPC:       creating workqueue nfsiod\n");
2414bf701b76SNeilBrown 	wq = alloc_workqueue("nfsiod", WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
24155746006fSTrond Myklebust 	if (wq == NULL)
24165746006fSTrond Myklebust 		return -ENOMEM;
24175746006fSTrond Myklebust 	nfsiod_workqueue = wq;
24185746006fSTrond Myklebust 	return 0;
24195746006fSTrond Myklebust }
24205746006fSTrond Myklebust 
24215746006fSTrond Myklebust /*
24225746006fSTrond Myklebust  * Destroy the nfsiod workqueue
24235746006fSTrond Myklebust  */
nfsiod_stop(void)24245746006fSTrond Myklebust static void nfsiod_stop(void)
24255746006fSTrond Myklebust {
24265746006fSTrond Myklebust 	struct workqueue_struct *wq;
24275746006fSTrond Myklebust 
24285746006fSTrond Myklebust 	wq = nfsiod_workqueue;
24295746006fSTrond Myklebust 	if (wq == NULL)
24305746006fSTrond Myklebust 		return;
24315746006fSTrond Myklebust 	nfsiod_workqueue = NULL;
24325746006fSTrond Myklebust 	destroy_workqueue(wq);
24335746006fSTrond Myklebust }
24345746006fSTrond Myklebust 
2435c7d03a00SAlexey Dobriyan unsigned int nfs_net_id;
24369e2e74dbSStanislav Kinsbursky EXPORT_SYMBOL_GPL(nfs_net_id);
24371b340d01SStanislav Kinsbursky 
nfs_net_init(struct net * net)24381b340d01SStanislav Kinsbursky static int nfs_net_init(struct net *net)
24391b340d01SStanislav Kinsbursky {
244026033322SJosef Bacik 	struct nfs_net *nn = net_generic(net, nfs_net_id);
244126033322SJosef Bacik 
24426b13168bSStanislav Kinsbursky 	nfs_clients_init(net);
24438a1f89c9SKuniyuki Iwashima 
24448a1f89c9SKuniyuki Iwashima 	if (!rpc_proc_register(net, &nn->rpcstats)) {
24458a1f89c9SKuniyuki Iwashima 		nfs_clients_exit(net);
24468a1f89c9SKuniyuki Iwashima 		return -ENOMEM;
24478a1f89c9SKuniyuki Iwashima 	}
24488a1f89c9SKuniyuki Iwashima 
244965b38851SEric W. Biederman 	return nfs_fs_proc_net_init(net);
24501b340d01SStanislav Kinsbursky }
24511b340d01SStanislav Kinsbursky 
nfs_net_exit(struct net * net)24521b340d01SStanislav Kinsbursky static void nfs_net_exit(struct net *net)
24531b340d01SStanislav Kinsbursky {
245453a0365cSJosef Bacik 	rpc_proc_unregister(net, "nfs");
245565b38851SEric W. Biederman 	nfs_fs_proc_net_exit(net);
245610b7a70cSTrond Myklebust 	nfs_clients_exit(net);
24571b340d01SStanislav Kinsbursky }
24581b340d01SStanislav Kinsbursky 
24591b340d01SStanislav Kinsbursky static struct pernet_operations nfs_net_ops = {
24601b340d01SStanislav Kinsbursky 	.init = nfs_net_init,
24611b340d01SStanislav Kinsbursky 	.exit = nfs_net_exit,
24621b340d01SStanislav Kinsbursky 	.id   = &nfs_net_id,
24631b340d01SStanislav Kinsbursky 	.size = sizeof(struct nfs_net),
24641b340d01SStanislav Kinsbursky };
24651b340d01SStanislav Kinsbursky 
24661da177e4SLinus Torvalds /*
24671da177e4SLinus Torvalds  * Initialize NFS
24681da177e4SLinus Torvalds  */
init_nfs_fs(void)24691da177e4SLinus Torvalds static int __init init_nfs_fs(void)
24701da177e4SLinus Torvalds {
24711da177e4SLinus Torvalds 	int err;
24721da177e4SLinus Torvalds 
2473996bc4f4STrond Myklebust 	err = nfs_sysfs_init();
2474996bc4f4STrond Myklebust 	if (err < 0)
2475996bc4f4STrond Myklebust 		goto out10;
2476996bc4f4STrond Myklebust 
24771b340d01SStanislav Kinsbursky 	err = register_pernet_subsys(&nfs_net_ops);
24781b340d01SStanislav Kinsbursky 	if (err < 0)
247989d77c8fSBryan Schumaker 		goto out9;
2480e571cbf1STrond Myklebust 
24815746006fSTrond Myklebust 	err = nfsiod_start();
24825746006fSTrond Myklebust 	if (err)
248389d77c8fSBryan Schumaker 		goto out7;
24845746006fSTrond Myklebust 
24856aaca566SDavid Howells 	err = nfs_fs_proc_init();
24866aaca566SDavid Howells 	if (err)
248789d77c8fSBryan Schumaker 		goto out6;
24886aaca566SDavid Howells 
24891da177e4SLinus Torvalds 	err = nfs_init_nfspagecache();
24901da177e4SLinus Torvalds 	if (err)
249189d77c8fSBryan Schumaker 		goto out5;
24921da177e4SLinus Torvalds 
24931da177e4SLinus Torvalds 	err = nfs_init_inodecache();
24941da177e4SLinus Torvalds 	if (err)
249589d77c8fSBryan Schumaker 		goto out4;
24961da177e4SLinus Torvalds 
24971da177e4SLinus Torvalds 	err = nfs_init_readpagecache();
24981da177e4SLinus Torvalds 	if (err)
249989d77c8fSBryan Schumaker 		goto out3;
25001da177e4SLinus Torvalds 
25011da177e4SLinus Torvalds 	err = nfs_init_writepagecache();
25021da177e4SLinus Torvalds 	if (err)
250389d77c8fSBryan Schumaker 		goto out2;
25041da177e4SLinus Torvalds 
25051da177e4SLinus Torvalds 	err = nfs_init_directcache();
25061da177e4SLinus Torvalds 	if (err)
250789d77c8fSBryan Schumaker 		goto out1;
25081da177e4SLinus Torvalds 
2509cd738ee9SKinglong Mee 	err = register_nfs_fs();
2510cd738ee9SKinglong Mee 	if (err)
2511129d1977SBryan Schumaker 		goto out0;
2512129d1977SBryan Schumaker 
25131da177e4SLinus Torvalds 	return 0;
2514129d1977SBryan Schumaker out0:
25151da177e4SLinus Torvalds 	nfs_destroy_directcache();
251689d77c8fSBryan Schumaker out1:
2517129d1977SBryan Schumaker 	nfs_destroy_writepagecache();
251889d77c8fSBryan Schumaker out2:
2519129d1977SBryan Schumaker 	nfs_destroy_readpagecache();
252089d77c8fSBryan Schumaker out3:
2521129d1977SBryan Schumaker 	nfs_destroy_inodecache();
252289d77c8fSBryan Schumaker out4:
2523129d1977SBryan Schumaker 	nfs_destroy_nfspagecache();
252489d77c8fSBryan Schumaker out5:
2525129d1977SBryan Schumaker 	nfs_fs_proc_exit();
252689d77c8fSBryan Schumaker out6:
2527129d1977SBryan Schumaker 	nfsiod_stop();
252889d77c8fSBryan Schumaker out7:
2529129d1977SBryan Schumaker 	unregister_pernet_subsys(&nfs_net_ops);
253089d77c8fSBryan Schumaker out9:
2531996bc4f4STrond Myklebust 	nfs_sysfs_exit();
2532996bc4f4STrond Myklebust out10:
25331da177e4SLinus Torvalds 	return err;
25341da177e4SLinus Torvalds }
25351da177e4SLinus Torvalds 
exit_nfs_fs(void)25361da177e4SLinus Torvalds static void __exit exit_nfs_fs(void)
25371da177e4SLinus Torvalds {
25381da177e4SLinus Torvalds 	nfs_destroy_directcache();
25391da177e4SLinus Torvalds 	nfs_destroy_writepagecache();
25401da177e4SLinus Torvalds 	nfs_destroy_readpagecache();
25411da177e4SLinus Torvalds 	nfs_destroy_inodecache();
25421da177e4SLinus Torvalds 	nfs_destroy_nfspagecache();
25431b340d01SStanislav Kinsbursky 	unregister_pernet_subsys(&nfs_net_ops);
2544f7b422b1SDavid Howells 	unregister_nfs_fs();
25456aaca566SDavid Howells 	nfs_fs_proc_exit();
25465746006fSTrond Myklebust 	nfsiod_stop();
2547996bc4f4STrond Myklebust 	nfs_sysfs_exit();
25481da177e4SLinus Torvalds }
25491da177e4SLinus Torvalds 
25501da177e4SLinus Torvalds /* Not quite true; I just maintain it */
25511da177e4SLinus Torvalds MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
25521da177e4SLinus Torvalds MODULE_LICENSE("GPL");
2553f43bf0beSTrond Myklebust module_param(enable_ino64, bool, 0644);
25541da177e4SLinus Torvalds 
25551da177e4SLinus Torvalds module_init(init_nfs_fs)
25561da177e4SLinus Torvalds module_exit(exit_nfs_fs)
2557