162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/nfs/inode.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1992 Rick Sladkey 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * nfs inode and superblock handling functions 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Modularised by Alan Cox <alan@lxorguk.ukuu.org.uk>, while hacking some 1062306a36Sopenharmony_ci * experimental NFS changes. Modularisation taken straight from SYS5 fs. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Change to nfs_read_super() to permit NFS mounts to multi-homed hosts. 1362306a36Sopenharmony_ci * J.S.Peatfield@damtp.cam.ac.uk 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/init.h> 1962306a36Sopenharmony_ci#include <linux/sched/signal.h> 2062306a36Sopenharmony_ci#include <linux/time.h> 2162306a36Sopenharmony_ci#include <linux/kernel.h> 2262306a36Sopenharmony_ci#include <linux/mm.h> 2362306a36Sopenharmony_ci#include <linux/string.h> 2462306a36Sopenharmony_ci#include <linux/stat.h> 2562306a36Sopenharmony_ci#include <linux/errno.h> 2662306a36Sopenharmony_ci#include <linux/unistd.h> 2762306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h> 2862306a36Sopenharmony_ci#include <linux/sunrpc/stats.h> 2962306a36Sopenharmony_ci#include <linux/sunrpc/metrics.h> 3062306a36Sopenharmony_ci#include <linux/nfs_fs.h> 3162306a36Sopenharmony_ci#include <linux/nfs_mount.h> 3262306a36Sopenharmony_ci#include <linux/nfs4_mount.h> 3362306a36Sopenharmony_ci#include <linux/lockd/bind.h> 3462306a36Sopenharmony_ci#include <linux/seq_file.h> 3562306a36Sopenharmony_ci#include <linux/mount.h> 3662306a36Sopenharmony_ci#include <linux/vfs.h> 3762306a36Sopenharmony_ci#include <linux/inet.h> 3862306a36Sopenharmony_ci#include <linux/nfs_xdr.h> 3962306a36Sopenharmony_ci#include <linux/slab.h> 4062306a36Sopenharmony_ci#include <linux/compat.h> 4162306a36Sopenharmony_ci#include <linux/freezer.h> 4262306a36Sopenharmony_ci#include <linux/uaccess.h> 4362306a36Sopenharmony_ci#include <linux/iversion.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include "nfs4_fs.h" 4662306a36Sopenharmony_ci#include "callback.h" 4762306a36Sopenharmony_ci#include "delegation.h" 4862306a36Sopenharmony_ci#include "iostat.h" 4962306a36Sopenharmony_ci#include "internal.h" 5062306a36Sopenharmony_ci#include "fscache.h" 5162306a36Sopenharmony_ci#include "pnfs.h" 5262306a36Sopenharmony_ci#include "nfs.h" 5362306a36Sopenharmony_ci#include "netns.h" 5462306a36Sopenharmony_ci#include "sysfs.h" 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#include "nfstrace.h" 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define NFSDBG_FACILITY NFSDBG_VFS 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define NFS_64_BIT_INODE_NUMBERS_ENABLED 1 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* Default is to see 64-bit inode numbers */ 6362306a36Sopenharmony_cistatic bool enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic int nfs_update_inode(struct inode *, struct nfs_fattr *); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic struct kmem_cache * nfs_inode_cachep; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic inline unsigned long 7062306a36Sopenharmony_cinfs_fattr_to_ino_t(struct nfs_fattr *fattr) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci return nfs_fileid_to_ino_t(fattr->fileid); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciint nfs_wait_bit_killable(struct wait_bit_key *key, int mode) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci schedule(); 7862306a36Sopenharmony_ci if (signal_pending_state(mode, current)) 7962306a36Sopenharmony_ci return -ERESTARTSYS; 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_wait_bit_killable); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/** 8562306a36Sopenharmony_ci * nfs_compat_user_ino64 - returns the user-visible inode number 8662306a36Sopenharmony_ci * @fileid: 64-bit fileid 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * This function returns a 32-bit inode number if the boot parameter 8962306a36Sopenharmony_ci * nfs.enable_ino64 is zero. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ciu64 nfs_compat_user_ino64(u64 fileid) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 9462306a36Sopenharmony_ci compat_ulong_t ino; 9562306a36Sopenharmony_ci#else 9662306a36Sopenharmony_ci unsigned long ino; 9762306a36Sopenharmony_ci#endif 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (enable_ino64) 10062306a36Sopenharmony_ci return fileid; 10162306a36Sopenharmony_ci ino = fileid; 10262306a36Sopenharmony_ci if (sizeof(ino) < sizeof(fileid)) 10362306a36Sopenharmony_ci ino ^= fileid >> (sizeof(fileid)-sizeof(ino)) * 8; 10462306a36Sopenharmony_ci return ino; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciint nfs_drop_inode(struct inode *inode) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci return NFS_STALE(inode) || generic_drop_inode(inode); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_drop_inode); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_civoid nfs_clear_inode(struct inode *inode) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * The following should never happen... 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci WARN_ON_ONCE(nfs_have_writebacks(inode)); 11962306a36Sopenharmony_ci WARN_ON_ONCE(!list_empty(&NFS_I(inode)->open_files)); 12062306a36Sopenharmony_ci nfs_zap_acl_cache(inode); 12162306a36Sopenharmony_ci nfs_access_zap_cache(inode); 12262306a36Sopenharmony_ci nfs_fscache_clear_inode(inode); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_clear_inode); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_civoid nfs_evict_inode(struct inode *inode) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci truncate_inode_pages_final(&inode->i_data); 12962306a36Sopenharmony_ci clear_inode(inode); 13062306a36Sopenharmony_ci nfs_clear_inode(inode); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ciint nfs_sync_inode(struct inode *inode) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci inode_dio_wait(inode); 13662306a36Sopenharmony_ci return nfs_wb_all(inode); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_sync_inode); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/** 14162306a36Sopenharmony_ci * nfs_sync_mapping - helper to flush all mmapped dirty data to disk 14262306a36Sopenharmony_ci * @mapping: pointer to struct address_space 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_ciint nfs_sync_mapping(struct address_space *mapping) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci int ret = 0; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (mapping->nrpages != 0) { 14962306a36Sopenharmony_ci unmap_mapping_range(mapping, 0, 0, 0); 15062306a36Sopenharmony_ci ret = nfs_wb_all(mapping->host); 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci return ret; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int nfs_attribute_timeout(struct inode *inode) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic bool nfs_check_cache_flags_invalid(struct inode *inode, 16362306a36Sopenharmony_ci unsigned long flags) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return (cache_validity & flags) != 0; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cibool nfs_check_cache_invalid(struct inode *inode, unsigned long flags) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci if (nfs_check_cache_flags_invalid(inode, flags)) 17362306a36Sopenharmony_ci return true; 17462306a36Sopenharmony_ci return nfs_attribute_cache_expired(inode); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_check_cache_invalid); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci#ifdef CONFIG_NFS_V4_2 17962306a36Sopenharmony_cistatic bool nfs_has_xattr_cache(const struct nfs_inode *nfsi) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci return nfsi->xattr_cache != NULL; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci#else 18462306a36Sopenharmony_cistatic bool nfs_has_xattr_cache(const struct nfs_inode *nfsi) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci return false; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci#endif 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_civoid nfs_set_cache_invalid(struct inode *inode, unsigned long flags) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 19362306a36Sopenharmony_ci bool have_delegation = NFS_PROTO(inode)->have_delegation(inode, FMODE_READ); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (have_delegation) { 19662306a36Sopenharmony_ci if (!(flags & NFS_INO_REVAL_FORCED)) 19762306a36Sopenharmony_ci flags &= ~(NFS_INO_INVALID_MODE | 19862306a36Sopenharmony_ci NFS_INO_INVALID_OTHER | 19962306a36Sopenharmony_ci NFS_INO_INVALID_XATTR); 20062306a36Sopenharmony_ci flags &= ~(NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (!nfs_has_xattr_cache(nfsi)) 20462306a36Sopenharmony_ci flags &= ~NFS_INO_INVALID_XATTR; 20562306a36Sopenharmony_ci if (flags & NFS_INO_INVALID_DATA) 20662306a36Sopenharmony_ci nfs_fscache_invalidate(inode, 0); 20762306a36Sopenharmony_ci flags &= ~NFS_INO_REVAL_FORCED; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci nfsi->cache_validity |= flags; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (inode->i_mapping->nrpages == 0) { 21262306a36Sopenharmony_ci nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; 21362306a36Sopenharmony_ci nfs_ooo_clear(nfsi); 21462306a36Sopenharmony_ci } else if (nfsi->cache_validity & NFS_INO_INVALID_DATA) { 21562306a36Sopenharmony_ci nfs_ooo_clear(nfsi); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci trace_nfs_set_cache_invalid(inode, 0); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_set_cache_invalid); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/* 22262306a36Sopenharmony_ci * Invalidate the local caches 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_cistatic void nfs_zap_caches_locked(struct inode *inode) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 22762306a36Sopenharmony_ci int mode = inode->i_mode; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); 23262306a36Sopenharmony_ci nfsi->attrtimeo_timestamp = jiffies; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) 23562306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR | 23662306a36Sopenharmony_ci NFS_INO_INVALID_DATA | 23762306a36Sopenharmony_ci NFS_INO_INVALID_ACCESS | 23862306a36Sopenharmony_ci NFS_INO_INVALID_ACL | 23962306a36Sopenharmony_ci NFS_INO_INVALID_XATTR); 24062306a36Sopenharmony_ci else 24162306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR | 24262306a36Sopenharmony_ci NFS_INO_INVALID_ACCESS | 24362306a36Sopenharmony_ci NFS_INO_INVALID_ACL | 24462306a36Sopenharmony_ci NFS_INO_INVALID_XATTR); 24562306a36Sopenharmony_ci nfs_zap_label_cache_locked(nfsi); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_civoid nfs_zap_caches(struct inode *inode) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci spin_lock(&inode->i_lock); 25162306a36Sopenharmony_ci nfs_zap_caches_locked(inode); 25262306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_civoid nfs_zap_mapping(struct inode *inode, struct address_space *mapping) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci if (mapping->nrpages != 0) { 25862306a36Sopenharmony_ci spin_lock(&inode->i_lock); 25962306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA); 26062306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_civoid nfs_zap_acl_cache(struct inode *inode) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci void (*clear_acl_cache)(struct inode *); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci clear_acl_cache = NFS_PROTO(inode)->clear_acl_cache; 26962306a36Sopenharmony_ci if (clear_acl_cache != NULL) 27062306a36Sopenharmony_ci clear_acl_cache(inode); 27162306a36Sopenharmony_ci spin_lock(&inode->i_lock); 27262306a36Sopenharmony_ci NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_ACL; 27362306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_zap_acl_cache); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_civoid nfs_invalidate_atime(struct inode *inode) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci spin_lock(&inode->i_lock); 28062306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME); 28162306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_invalidate_atime); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci/* 28662306a36Sopenharmony_ci * Invalidate, but do not unhash, the inode. 28762306a36Sopenharmony_ci * NB: must be called with inode->i_lock held! 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_cistatic void nfs_set_inode_stale_locked(struct inode *inode) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); 29262306a36Sopenharmony_ci nfs_zap_caches_locked(inode); 29362306a36Sopenharmony_ci trace_nfs_set_inode_stale(inode); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_civoid nfs_set_inode_stale(struct inode *inode) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci spin_lock(&inode->i_lock); 29962306a36Sopenharmony_ci nfs_set_inode_stale_locked(inode); 30062306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistruct nfs_find_desc { 30462306a36Sopenharmony_ci struct nfs_fh *fh; 30562306a36Sopenharmony_ci struct nfs_fattr *fattr; 30662306a36Sopenharmony_ci}; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci/* 30962306a36Sopenharmony_ci * In NFSv3 we can have 64bit inode numbers. In order to support 31062306a36Sopenharmony_ci * this, and re-exported directories (also seen in NFSv2) 31162306a36Sopenharmony_ci * we are forced to allow 2 different inodes to have the same 31262306a36Sopenharmony_ci * i_ino. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_cistatic int 31562306a36Sopenharmony_cinfs_find_actor(struct inode *inode, void *opaque) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct nfs_find_desc *desc = opaque; 31862306a36Sopenharmony_ci struct nfs_fh *fh = desc->fh; 31962306a36Sopenharmony_ci struct nfs_fattr *fattr = desc->fattr; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (NFS_FILEID(inode) != fattr->fileid) 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci if (inode_wrong_type(inode, fattr->mode)) 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci if (nfs_compare_fh(NFS_FH(inode), fh)) 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci if (is_bad_inode(inode) || NFS_STALE(inode)) 32862306a36Sopenharmony_ci return 0; 32962306a36Sopenharmony_ci return 1; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic int 33362306a36Sopenharmony_cinfs_init_locked(struct inode *inode, void *opaque) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct nfs_find_desc *desc = opaque; 33662306a36Sopenharmony_ci struct nfs_fattr *fattr = desc->fattr; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci set_nfs_fileid(inode, fattr->fileid); 33962306a36Sopenharmony_ci inode->i_mode = fattr->mode; 34062306a36Sopenharmony_ci nfs_copy_fh(NFS_FH(inode), desc->fh); 34162306a36Sopenharmony_ci return 0; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci#ifdef CONFIG_NFS_V4_SECURITY_LABEL 34562306a36Sopenharmony_cistatic void nfs_clear_label_invalid(struct inode *inode) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci spin_lock(&inode->i_lock); 34862306a36Sopenharmony_ci NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_LABEL; 34962306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_civoid nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci int error; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (fattr->label == NULL) 35762306a36Sopenharmony_ci return; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL) && inode->i_security) { 36062306a36Sopenharmony_ci error = security_inode_notifysecctx(inode, fattr->label->label, 36162306a36Sopenharmony_ci fattr->label->len); 36262306a36Sopenharmony_ci if (error) 36362306a36Sopenharmony_ci printk(KERN_ERR "%s() %s %d " 36462306a36Sopenharmony_ci "security_inode_notifysecctx() %d\n", 36562306a36Sopenharmony_ci __func__, 36662306a36Sopenharmony_ci (char *)fattr->label->label, 36762306a36Sopenharmony_ci fattr->label->len, error); 36862306a36Sopenharmony_ci nfs_clear_label_invalid(inode); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistruct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct nfs4_label *label; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (!(server->caps & NFS_CAP_SECURITY_LABEL)) 37762306a36Sopenharmony_ci return NULL; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci label = kzalloc(sizeof(struct nfs4_label), flags); 38062306a36Sopenharmony_ci if (label == NULL) 38162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci label->label = kzalloc(NFS4_MAXLABELLEN, flags); 38462306a36Sopenharmony_ci if (label->label == NULL) { 38562306a36Sopenharmony_ci kfree(label); 38662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci label->len = NFS4_MAXLABELLEN; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return label; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_label_alloc); 39362306a36Sopenharmony_ci#else 39462306a36Sopenharmony_civoid nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci#endif 39862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_setsecurity); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/* Search for inode identified by fh, fileid and i_mode in inode cache. */ 40162306a36Sopenharmony_cistruct inode * 40262306a36Sopenharmony_cinfs_ilookup(struct super_block *sb, struct nfs_fattr *fattr, struct nfs_fh *fh) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct nfs_find_desc desc = { 40562306a36Sopenharmony_ci .fh = fh, 40662306a36Sopenharmony_ci .fattr = fattr, 40762306a36Sopenharmony_ci }; 40862306a36Sopenharmony_ci struct inode *inode; 40962306a36Sopenharmony_ci unsigned long hash; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (!(fattr->valid & NFS_ATTR_FATTR_FILEID) || 41262306a36Sopenharmony_ci !(fattr->valid & NFS_ATTR_FATTR_TYPE)) 41362306a36Sopenharmony_ci return NULL; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci hash = nfs_fattr_to_ino_t(fattr); 41662306a36Sopenharmony_ci inode = ilookup5(sb, hash, nfs_find_actor, &desc); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci dprintk("%s: returning %p\n", __func__, inode); 41962306a36Sopenharmony_ci return inode; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic void nfs_inode_init_regular(struct nfs_inode *nfsi) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci atomic_long_set(&nfsi->nrequests, 0); 42562306a36Sopenharmony_ci atomic_long_set(&nfsi->redirtied_pages, 0); 42662306a36Sopenharmony_ci INIT_LIST_HEAD(&nfsi->commit_info.list); 42762306a36Sopenharmony_ci atomic_long_set(&nfsi->commit_info.ncommit, 0); 42862306a36Sopenharmony_ci atomic_set(&nfsi->commit_info.rpcs_out, 0); 42962306a36Sopenharmony_ci mutex_init(&nfsi->commit_mutex); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic void nfs_inode_init_dir(struct nfs_inode *nfsi) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci nfsi->cache_change_attribute = 0; 43562306a36Sopenharmony_ci memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); 43662306a36Sopenharmony_ci init_rwsem(&nfsi->rmdir_sem); 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/* 44062306a36Sopenharmony_ci * This is our front-end to iget that looks up inodes by file handle 44162306a36Sopenharmony_ci * instead of inode number. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_cistruct inode * 44462306a36Sopenharmony_cinfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct nfs_find_desc desc = { 44762306a36Sopenharmony_ci .fh = fh, 44862306a36Sopenharmony_ci .fattr = fattr 44962306a36Sopenharmony_ci }; 45062306a36Sopenharmony_ci struct inode *inode = ERR_PTR(-ENOENT); 45162306a36Sopenharmony_ci u64 fattr_supported = NFS_SB(sb)->fattr_valid; 45262306a36Sopenharmony_ci unsigned long hash; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci nfs_attr_check_mountpoint(sb, fattr); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (nfs_attr_use_mounted_on_fileid(fattr)) 45762306a36Sopenharmony_ci fattr->fileid = fattr->mounted_on_fileid; 45862306a36Sopenharmony_ci else if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0) 45962306a36Sopenharmony_ci goto out_no_inode; 46062306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0) 46162306a36Sopenharmony_ci goto out_no_inode; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci hash = nfs_fattr_to_ino_t(fattr); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc); 46662306a36Sopenharmony_ci if (inode == NULL) { 46762306a36Sopenharmony_ci inode = ERR_PTR(-ENOMEM); 46862306a36Sopenharmony_ci goto out_no_inode; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (inode->i_state & I_NEW) { 47262306a36Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 47362306a36Sopenharmony_ci unsigned long now = jiffies; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* We set i_ino for the few things that still rely on it, 47662306a36Sopenharmony_ci * such as stat(2) */ 47762306a36Sopenharmony_ci inode->i_ino = hash; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* We can't support update_atime(), since the server will reset it */ 48062306a36Sopenharmony_ci inode->i_flags |= S_NOATIME|S_NOCMTIME; 48162306a36Sopenharmony_ci inode->i_mode = fattr->mode; 48262306a36Sopenharmony_ci nfsi->cache_validity = 0; 48362306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0 48462306a36Sopenharmony_ci && (fattr_supported & NFS_ATTR_FATTR_MODE)) 48562306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_MODE); 48662306a36Sopenharmony_ci /* Why so? Because we want revalidate for devices/FIFOs, and 48762306a36Sopenharmony_ci * that's precisely what we have in nfs_file_inode_operations. 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_ci inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops; 49062306a36Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 49162306a36Sopenharmony_ci inode->i_fop = NFS_SB(sb)->nfs_client->rpc_ops->file_ops; 49262306a36Sopenharmony_ci inode->i_data.a_ops = &nfs_file_aops; 49362306a36Sopenharmony_ci nfs_inode_init_regular(nfsi); 49462306a36Sopenharmony_ci } else if (S_ISDIR(inode->i_mode)) { 49562306a36Sopenharmony_ci inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops; 49662306a36Sopenharmony_ci inode->i_fop = &nfs_dir_operations; 49762306a36Sopenharmony_ci inode->i_data.a_ops = &nfs_dir_aops; 49862306a36Sopenharmony_ci nfs_inode_init_dir(nfsi); 49962306a36Sopenharmony_ci /* Deal with crossing mountpoints */ 50062306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT || 50162306a36Sopenharmony_ci fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { 50262306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) 50362306a36Sopenharmony_ci inode->i_op = &nfs_referral_inode_operations; 50462306a36Sopenharmony_ci else 50562306a36Sopenharmony_ci inode->i_op = &nfs_mountpoint_inode_operations; 50662306a36Sopenharmony_ci inode->i_fop = NULL; 50762306a36Sopenharmony_ci inode->i_flags |= S_AUTOMOUNT; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci } else if (S_ISLNK(inode->i_mode)) { 51062306a36Sopenharmony_ci inode->i_op = &nfs_symlink_inode_operations; 51162306a36Sopenharmony_ci inode_nohighmem(inode); 51262306a36Sopenharmony_ci } else 51362306a36Sopenharmony_ci init_special_inode(inode, inode->i_mode, fattr->rdev); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci memset(&inode->i_atime, 0, sizeof(inode->i_atime)); 51662306a36Sopenharmony_ci memset(&inode->i_mtime, 0, sizeof(inode->i_mtime)); 51762306a36Sopenharmony_ci inode_set_ctime(inode, 0, 0); 51862306a36Sopenharmony_ci inode_set_iversion_raw(inode, 0); 51962306a36Sopenharmony_ci inode->i_size = 0; 52062306a36Sopenharmony_ci clear_nlink(inode); 52162306a36Sopenharmony_ci inode->i_uid = make_kuid(&init_user_ns, -2); 52262306a36Sopenharmony_ci inode->i_gid = make_kgid(&init_user_ns, -2); 52362306a36Sopenharmony_ci inode->i_blocks = 0; 52462306a36Sopenharmony_ci nfsi->write_io = 0; 52562306a36Sopenharmony_ci nfsi->read_io = 0; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci nfsi->read_cache_jiffies = fattr->time_start; 52862306a36Sopenharmony_ci nfsi->attr_gencount = fattr->gencount; 52962306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_ATIME) 53062306a36Sopenharmony_ci inode->i_atime = fattr->atime; 53162306a36Sopenharmony_ci else if (fattr_supported & NFS_ATTR_FATTR_ATIME) 53262306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME); 53362306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MTIME) 53462306a36Sopenharmony_ci inode->i_mtime = fattr->mtime; 53562306a36Sopenharmony_ci else if (fattr_supported & NFS_ATTR_FATTR_MTIME) 53662306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME); 53762306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CTIME) 53862306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, fattr->ctime); 53962306a36Sopenharmony_ci else if (fattr_supported & NFS_ATTR_FATTR_CTIME) 54062306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_CTIME); 54162306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CHANGE) 54262306a36Sopenharmony_ci inode_set_iversion_raw(inode, fattr->change_attr); 54362306a36Sopenharmony_ci else 54462306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE); 54562306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_SIZE) 54662306a36Sopenharmony_ci inode->i_size = nfs_size_to_loff_t(fattr->size); 54762306a36Sopenharmony_ci else 54862306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_SIZE); 54962306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_NLINK) 55062306a36Sopenharmony_ci set_nlink(inode, fattr->nlink); 55162306a36Sopenharmony_ci else if (fattr_supported & NFS_ATTR_FATTR_NLINK) 55262306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_NLINK); 55362306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_OWNER) 55462306a36Sopenharmony_ci inode->i_uid = fattr->uid; 55562306a36Sopenharmony_ci else if (fattr_supported & NFS_ATTR_FATTR_OWNER) 55662306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER); 55762306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_GROUP) 55862306a36Sopenharmony_ci inode->i_gid = fattr->gid; 55962306a36Sopenharmony_ci else if (fattr_supported & NFS_ATTR_FATTR_GROUP) 56062306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER); 56162306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) 56262306a36Sopenharmony_ci inode->i_blocks = fattr->du.nfs2.blocks; 56362306a36Sopenharmony_ci else if (fattr_supported & NFS_ATTR_FATTR_BLOCKS_USED && 56462306a36Sopenharmony_ci fattr->size != 0) 56562306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS); 56662306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { 56762306a36Sopenharmony_ci /* 56862306a36Sopenharmony_ci * report the blocks in 512byte units 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ci inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); 57162306a36Sopenharmony_ci } else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED && 57262306a36Sopenharmony_ci fattr->size != 0) 57362306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_BLOCKS); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci nfs_setsecurity(inode, fattr); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); 57862306a36Sopenharmony_ci nfsi->attrtimeo_timestamp = now; 57962306a36Sopenharmony_ci nfsi->access_cache = RB_ROOT; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci nfs_fscache_init_inode(inode); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci unlock_new_inode(inode); 58462306a36Sopenharmony_ci } else { 58562306a36Sopenharmony_ci int err = nfs_refresh_inode(inode, fattr); 58662306a36Sopenharmony_ci if (err < 0) { 58762306a36Sopenharmony_ci iput(inode); 58862306a36Sopenharmony_ci inode = ERR_PTR(err); 58962306a36Sopenharmony_ci goto out_no_inode; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci dprintk("NFS: nfs_fhget(%s/%Lu fh_crc=0x%08x ct=%d)\n", 59362306a36Sopenharmony_ci inode->i_sb->s_id, 59462306a36Sopenharmony_ci (unsigned long long)NFS_FILEID(inode), 59562306a36Sopenharmony_ci nfs_display_fhandle_hash(fh), 59662306a36Sopenharmony_ci atomic_read(&inode->i_count)); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ciout: 59962306a36Sopenharmony_ci return inode; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ciout_no_inode: 60262306a36Sopenharmony_ci dprintk("nfs_fhget: iget failed with error %ld\n", PTR_ERR(inode)); 60362306a36Sopenharmony_ci goto out; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_fhget); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci#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) 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ciint 61062306a36Sopenharmony_cinfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 61162306a36Sopenharmony_ci struct iattr *attr) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 61462306a36Sopenharmony_ci struct nfs_fattr *fattr; 61562306a36Sopenharmony_ci int error = 0; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_VFSSETATTR); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* skip mode change if it's just for clearing setuid/setgid */ 62062306a36Sopenharmony_ci if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) 62162306a36Sopenharmony_ci attr->ia_valid &= ~ATTR_MODE; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (attr->ia_valid & ATTR_SIZE) { 62462306a36Sopenharmony_ci BUG_ON(!S_ISREG(inode->i_mode)); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci error = inode_newsize_ok(inode, attr->ia_size); 62762306a36Sopenharmony_ci if (error) 62862306a36Sopenharmony_ci return error; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (attr->ia_size == i_size_read(inode)) 63162306a36Sopenharmony_ci attr->ia_valid &= ~ATTR_SIZE; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* Optimization: if the end result is no change, don't RPC */ 63562306a36Sopenharmony_ci if (((attr->ia_valid & NFS_VALID_ATTRS) & ~(ATTR_FILE|ATTR_OPEN)) == 0) 63662306a36Sopenharmony_ci return 0; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci trace_nfs_setattr_enter(inode); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* Write all dirty data */ 64162306a36Sopenharmony_ci if (S_ISREG(inode->i_mode)) 64262306a36Sopenharmony_ci nfs_sync_inode(inode); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci fattr = nfs_alloc_fattr_with_label(NFS_SERVER(inode)); 64562306a36Sopenharmony_ci if (fattr == NULL) { 64662306a36Sopenharmony_ci error = -ENOMEM; 64762306a36Sopenharmony_ci goto out; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); 65162306a36Sopenharmony_ci if (error == 0) 65262306a36Sopenharmony_ci error = nfs_refresh_inode(inode, fattr); 65362306a36Sopenharmony_ci nfs_free_fattr(fattr); 65462306a36Sopenharmony_ciout: 65562306a36Sopenharmony_ci trace_nfs_setattr_exit(inode, error); 65662306a36Sopenharmony_ci return error; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_setattr); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci/** 66162306a36Sopenharmony_ci * nfs_vmtruncate - unmap mappings "freed" by truncate() syscall 66262306a36Sopenharmony_ci * @inode: inode of the file used 66362306a36Sopenharmony_ci * @offset: file offset to start truncating 66462306a36Sopenharmony_ci * 66562306a36Sopenharmony_ci * This is a copy of the common vmtruncate, but with the locking 66662306a36Sopenharmony_ci * corrected to take into account the fact that NFS requires 66762306a36Sopenharmony_ci * inode->i_size to be updated under the inode->i_lock. 66862306a36Sopenharmony_ci * Note: must be called with inode->i_lock held! 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_cistatic int nfs_vmtruncate(struct inode * inode, loff_t offset) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci int err; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci err = inode_newsize_ok(inode, offset); 67562306a36Sopenharmony_ci if (err) 67662306a36Sopenharmony_ci goto out; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci trace_nfs_size_truncate(inode, offset); 67962306a36Sopenharmony_ci i_size_write(inode, offset); 68062306a36Sopenharmony_ci /* Optimisation */ 68162306a36Sopenharmony_ci if (offset == 0) { 68262306a36Sopenharmony_ci NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_DATA; 68362306a36Sopenharmony_ci nfs_ooo_clear(NFS_I(inode)); 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_SIZE; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 68862306a36Sopenharmony_ci truncate_pagecache(inode, offset); 68962306a36Sopenharmony_ci spin_lock(&inode->i_lock); 69062306a36Sopenharmony_ciout: 69162306a36Sopenharmony_ci return err; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci/** 69562306a36Sopenharmony_ci * nfs_setattr_update_inode - Update inode metadata after a setattr call. 69662306a36Sopenharmony_ci * @inode: pointer to struct inode 69762306a36Sopenharmony_ci * @attr: pointer to struct iattr 69862306a36Sopenharmony_ci * @fattr: pointer to struct nfs_fattr 69962306a36Sopenharmony_ci * 70062306a36Sopenharmony_ci * Note: we do this in the *proc.c in order to ensure that 70162306a36Sopenharmony_ci * it works for things like exclusive creates too. 70262306a36Sopenharmony_ci */ 70362306a36Sopenharmony_civoid nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, 70462306a36Sopenharmony_ci struct nfs_fattr *fattr) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci /* Barrier: bump the attribute generation count. */ 70762306a36Sopenharmony_ci nfs_fattr_set_barrier(fattr); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci spin_lock(&inode->i_lock); 71062306a36Sopenharmony_ci NFS_I(inode)->attr_gencount = fattr->gencount; 71162306a36Sopenharmony_ci if ((attr->ia_valid & ATTR_SIZE) != 0) { 71262306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME | 71362306a36Sopenharmony_ci NFS_INO_INVALID_BLOCKS); 71462306a36Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC); 71562306a36Sopenharmony_ci nfs_vmtruncate(inode, attr->ia_size); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) { 71862306a36Sopenharmony_ci NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_CTIME; 71962306a36Sopenharmony_ci if ((attr->ia_valid & ATTR_KILL_SUID) != 0 && 72062306a36Sopenharmony_ci inode->i_mode & S_ISUID) 72162306a36Sopenharmony_ci inode->i_mode &= ~S_ISUID; 72262306a36Sopenharmony_ci if (setattr_should_drop_sgid(&nop_mnt_idmap, inode)) 72362306a36Sopenharmony_ci inode->i_mode &= ~S_ISGID; 72462306a36Sopenharmony_ci if ((attr->ia_valid & ATTR_MODE) != 0) { 72562306a36Sopenharmony_ci int mode = attr->ia_mode & S_IALLUGO; 72662306a36Sopenharmony_ci mode |= inode->i_mode & ~S_IALLUGO; 72762306a36Sopenharmony_ci inode->i_mode = mode; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci if ((attr->ia_valid & ATTR_UID) != 0) 73062306a36Sopenharmony_ci inode->i_uid = attr->ia_uid; 73162306a36Sopenharmony_ci if ((attr->ia_valid & ATTR_GID) != 0) 73262306a36Sopenharmony_ci inode->i_gid = attr->ia_gid; 73362306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CTIME) 73462306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, fattr->ctime); 73562306a36Sopenharmony_ci else 73662306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE 73762306a36Sopenharmony_ci | NFS_INO_INVALID_CTIME); 73862306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS 73962306a36Sopenharmony_ci | NFS_INO_INVALID_ACL); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci if (attr->ia_valid & (ATTR_ATIME_SET|ATTR_ATIME)) { 74262306a36Sopenharmony_ci NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_ATIME 74362306a36Sopenharmony_ci | NFS_INO_INVALID_CTIME); 74462306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_ATIME) 74562306a36Sopenharmony_ci inode->i_atime = fattr->atime; 74662306a36Sopenharmony_ci else if (attr->ia_valid & ATTR_ATIME_SET) 74762306a36Sopenharmony_ci inode->i_atime = attr->ia_atime; 74862306a36Sopenharmony_ci else 74962306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CTIME) 75262306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, fattr->ctime); 75362306a36Sopenharmony_ci else 75462306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE 75562306a36Sopenharmony_ci | NFS_INO_INVALID_CTIME); 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci if (attr->ia_valid & (ATTR_MTIME_SET|ATTR_MTIME)) { 75862306a36Sopenharmony_ci NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_MTIME 75962306a36Sopenharmony_ci | NFS_INO_INVALID_CTIME); 76062306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MTIME) 76162306a36Sopenharmony_ci inode->i_mtime = fattr->mtime; 76262306a36Sopenharmony_ci else if (attr->ia_valid & ATTR_MTIME_SET) 76362306a36Sopenharmony_ci inode->i_mtime = attr->ia_mtime; 76462306a36Sopenharmony_ci else 76562306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CTIME) 76862306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, fattr->ctime); 76962306a36Sopenharmony_ci else 77062306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE 77162306a36Sopenharmony_ci | NFS_INO_INVALID_CTIME); 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci if (fattr->valid) 77462306a36Sopenharmony_ci nfs_update_inode(inode, fattr); 77562306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_setattr_update_inode); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci/* 78062306a36Sopenharmony_ci * Don't request help from readdirplus if the file is being written to, 78162306a36Sopenharmony_ci * or if attribute caching is turned off 78262306a36Sopenharmony_ci */ 78362306a36Sopenharmony_cistatic bool nfs_getattr_readdirplus_enable(const struct inode *inode) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci return nfs_server_capable(inode, NFS_CAP_READDIRPLUS) && 78662306a36Sopenharmony_ci !nfs_have_writebacks(inode) && NFS_MAXATTRTIMEO(inode) > 5 * HZ; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic void nfs_readdirplus_parent_cache_miss(struct dentry *dentry) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci if (!IS_ROOT(dentry)) { 79262306a36Sopenharmony_ci struct dentry *parent = dget_parent(dentry); 79362306a36Sopenharmony_ci nfs_readdir_record_entry_cache_miss(d_inode(parent)); 79462306a36Sopenharmony_ci dput(parent); 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic void nfs_readdirplus_parent_cache_hit(struct dentry *dentry) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci if (!IS_ROOT(dentry)) { 80162306a36Sopenharmony_ci struct dentry *parent = dget_parent(dentry); 80262306a36Sopenharmony_ci nfs_readdir_record_entry_cache_hit(d_inode(parent)); 80362306a36Sopenharmony_ci dput(parent); 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic u32 nfs_get_valid_attrmask(struct inode *inode) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity); 81062306a36Sopenharmony_ci u32 reply_mask = STATX_INO | STATX_TYPE; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci if (!(cache_validity & NFS_INO_INVALID_ATIME)) 81362306a36Sopenharmony_ci reply_mask |= STATX_ATIME; 81462306a36Sopenharmony_ci if (!(cache_validity & NFS_INO_INVALID_CTIME)) 81562306a36Sopenharmony_ci reply_mask |= STATX_CTIME; 81662306a36Sopenharmony_ci if (!(cache_validity & NFS_INO_INVALID_MTIME)) 81762306a36Sopenharmony_ci reply_mask |= STATX_MTIME; 81862306a36Sopenharmony_ci if (!(cache_validity & NFS_INO_INVALID_SIZE)) 81962306a36Sopenharmony_ci reply_mask |= STATX_SIZE; 82062306a36Sopenharmony_ci if (!(cache_validity & NFS_INO_INVALID_NLINK)) 82162306a36Sopenharmony_ci reply_mask |= STATX_NLINK; 82262306a36Sopenharmony_ci if (!(cache_validity & NFS_INO_INVALID_MODE)) 82362306a36Sopenharmony_ci reply_mask |= STATX_MODE; 82462306a36Sopenharmony_ci if (!(cache_validity & NFS_INO_INVALID_OTHER)) 82562306a36Sopenharmony_ci reply_mask |= STATX_UID | STATX_GID; 82662306a36Sopenharmony_ci if (!(cache_validity & NFS_INO_INVALID_BLOCKS)) 82762306a36Sopenharmony_ci reply_mask |= STATX_BLOCKS; 82862306a36Sopenharmony_ci if (!(cache_validity & NFS_INO_INVALID_CHANGE)) 82962306a36Sopenharmony_ci reply_mask |= STATX_CHANGE_COOKIE; 83062306a36Sopenharmony_ci return reply_mask; 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ciint nfs_getattr(struct mnt_idmap *idmap, const struct path *path, 83462306a36Sopenharmony_ci struct kstat *stat, u32 request_mask, unsigned int query_flags) 83562306a36Sopenharmony_ci{ 83662306a36Sopenharmony_ci struct inode *inode = d_inode(path->dentry); 83762306a36Sopenharmony_ci struct nfs_server *server = NFS_SERVER(inode); 83862306a36Sopenharmony_ci unsigned long cache_validity; 83962306a36Sopenharmony_ci int err = 0; 84062306a36Sopenharmony_ci bool force_sync = query_flags & AT_STATX_FORCE_SYNC; 84162306a36Sopenharmony_ci bool do_update = false; 84262306a36Sopenharmony_ci bool readdirplus_enabled = nfs_getattr_readdirplus_enable(inode); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci trace_nfs_getattr_enter(inode); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci request_mask &= STATX_TYPE | STATX_MODE | STATX_NLINK | STATX_UID | 84762306a36Sopenharmony_ci STATX_GID | STATX_ATIME | STATX_MTIME | STATX_CTIME | 84862306a36Sopenharmony_ci STATX_INO | STATX_SIZE | STATX_BLOCKS | 84962306a36Sopenharmony_ci STATX_CHANGE_COOKIE; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) { 85262306a36Sopenharmony_ci if (readdirplus_enabled) 85362306a36Sopenharmony_ci nfs_readdirplus_parent_cache_hit(path->dentry); 85462306a36Sopenharmony_ci goto out_no_revalidate; 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* Flush out writes to the server in order to update c/mtime/version. */ 85862306a36Sopenharmony_ci if ((request_mask & (STATX_CTIME | STATX_MTIME | STATX_CHANGE_COOKIE)) && 85962306a36Sopenharmony_ci S_ISREG(inode->i_mode)) 86062306a36Sopenharmony_ci filemap_write_and_wait(inode->i_mapping); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* 86362306a36Sopenharmony_ci * We may force a getattr if the user cares about atime. 86462306a36Sopenharmony_ci * 86562306a36Sopenharmony_ci * Note that we only have to check the vfsmount flags here: 86662306a36Sopenharmony_ci * - NFS always sets S_NOATIME by so checking it would give a 86762306a36Sopenharmony_ci * bogus result 86862306a36Sopenharmony_ci * - NFS never sets SB_NOATIME or SB_NODIRATIME so there is 86962306a36Sopenharmony_ci * no point in checking those. 87062306a36Sopenharmony_ci */ 87162306a36Sopenharmony_ci if ((path->mnt->mnt_flags & MNT_NOATIME) || 87262306a36Sopenharmony_ci ((path->mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))) 87362306a36Sopenharmony_ci request_mask &= ~STATX_ATIME; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* Is the user requesting attributes that might need revalidation? */ 87662306a36Sopenharmony_ci if (!(request_mask & (STATX_MODE|STATX_NLINK|STATX_ATIME|STATX_CTIME| 87762306a36Sopenharmony_ci STATX_MTIME|STATX_UID|STATX_GID| 87862306a36Sopenharmony_ci STATX_SIZE|STATX_BLOCKS| 87962306a36Sopenharmony_ci STATX_CHANGE_COOKIE))) 88062306a36Sopenharmony_ci goto out_no_revalidate; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* Check whether the cached attributes are stale */ 88362306a36Sopenharmony_ci do_update |= force_sync || nfs_attribute_cache_expired(inode); 88462306a36Sopenharmony_ci cache_validity = READ_ONCE(NFS_I(inode)->cache_validity); 88562306a36Sopenharmony_ci do_update |= cache_validity & NFS_INO_INVALID_CHANGE; 88662306a36Sopenharmony_ci if (request_mask & STATX_ATIME) 88762306a36Sopenharmony_ci do_update |= cache_validity & NFS_INO_INVALID_ATIME; 88862306a36Sopenharmony_ci if (request_mask & STATX_CTIME) 88962306a36Sopenharmony_ci do_update |= cache_validity & NFS_INO_INVALID_CTIME; 89062306a36Sopenharmony_ci if (request_mask & STATX_MTIME) 89162306a36Sopenharmony_ci do_update |= cache_validity & NFS_INO_INVALID_MTIME; 89262306a36Sopenharmony_ci if (request_mask & STATX_SIZE) 89362306a36Sopenharmony_ci do_update |= cache_validity & NFS_INO_INVALID_SIZE; 89462306a36Sopenharmony_ci if (request_mask & STATX_NLINK) 89562306a36Sopenharmony_ci do_update |= cache_validity & NFS_INO_INVALID_NLINK; 89662306a36Sopenharmony_ci if (request_mask & STATX_MODE) 89762306a36Sopenharmony_ci do_update |= cache_validity & NFS_INO_INVALID_MODE; 89862306a36Sopenharmony_ci if (request_mask & (STATX_UID | STATX_GID)) 89962306a36Sopenharmony_ci do_update |= cache_validity & NFS_INO_INVALID_OTHER; 90062306a36Sopenharmony_ci if (request_mask & STATX_BLOCKS) 90162306a36Sopenharmony_ci do_update |= cache_validity & NFS_INO_INVALID_BLOCKS; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (do_update) { 90462306a36Sopenharmony_ci if (readdirplus_enabled) 90562306a36Sopenharmony_ci nfs_readdirplus_parent_cache_miss(path->dentry); 90662306a36Sopenharmony_ci err = __nfs_revalidate_inode(server, inode); 90762306a36Sopenharmony_ci if (err) 90862306a36Sopenharmony_ci goto out; 90962306a36Sopenharmony_ci } else if (readdirplus_enabled) 91062306a36Sopenharmony_ci nfs_readdirplus_parent_cache_hit(path->dentry); 91162306a36Sopenharmony_ciout_no_revalidate: 91262306a36Sopenharmony_ci /* Only return attributes that were revalidated. */ 91362306a36Sopenharmony_ci stat->result_mask = nfs_get_valid_attrmask(inode) | request_mask; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); 91662306a36Sopenharmony_ci stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode)); 91762306a36Sopenharmony_ci stat->change_cookie = inode_peek_iversion_raw(inode); 91862306a36Sopenharmony_ci stat->attributes_mask |= STATX_ATTR_CHANGE_MONOTONIC; 91962306a36Sopenharmony_ci if (server->change_attr_type != NFS4_CHANGE_TYPE_IS_UNDEFINED) 92062306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_CHANGE_MONOTONIC; 92162306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 92262306a36Sopenharmony_ci stat->blksize = NFS_SERVER(inode)->dtsize; 92362306a36Sopenharmony_ciout: 92462306a36Sopenharmony_ci trace_nfs_getattr_exit(inode, err); 92562306a36Sopenharmony_ci return err; 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_getattr); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_cistatic void nfs_init_lock_context(struct nfs_lock_context *l_ctx) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci refcount_set(&l_ctx->count, 1); 93262306a36Sopenharmony_ci l_ctx->lockowner = current->files; 93362306a36Sopenharmony_ci INIT_LIST_HEAD(&l_ctx->list); 93462306a36Sopenharmony_ci atomic_set(&l_ctx->io_count, 0); 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci struct nfs_lock_context *pos; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci list_for_each_entry_rcu(pos, &ctx->lock_context.list, list) { 94262306a36Sopenharmony_ci if (pos->lockowner != current->files) 94362306a36Sopenharmony_ci continue; 94462306a36Sopenharmony_ci if (refcount_inc_not_zero(&pos->count)) 94562306a36Sopenharmony_ci return pos; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci return NULL; 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistruct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci struct nfs_lock_context *res, *new = NULL; 95362306a36Sopenharmony_ci struct inode *inode = d_inode(ctx->dentry); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci rcu_read_lock(); 95662306a36Sopenharmony_ci res = __nfs_find_lock_context(ctx); 95762306a36Sopenharmony_ci rcu_read_unlock(); 95862306a36Sopenharmony_ci if (res == NULL) { 95962306a36Sopenharmony_ci new = kmalloc(sizeof(*new), GFP_KERNEL_ACCOUNT); 96062306a36Sopenharmony_ci if (new == NULL) 96162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 96262306a36Sopenharmony_ci nfs_init_lock_context(new); 96362306a36Sopenharmony_ci spin_lock(&inode->i_lock); 96462306a36Sopenharmony_ci res = __nfs_find_lock_context(ctx); 96562306a36Sopenharmony_ci if (res == NULL) { 96662306a36Sopenharmony_ci new->open_context = get_nfs_open_context(ctx); 96762306a36Sopenharmony_ci if (new->open_context) { 96862306a36Sopenharmony_ci list_add_tail_rcu(&new->list, 96962306a36Sopenharmony_ci &ctx->lock_context.list); 97062306a36Sopenharmony_ci res = new; 97162306a36Sopenharmony_ci new = NULL; 97262306a36Sopenharmony_ci } else 97362306a36Sopenharmony_ci res = ERR_PTR(-EBADF); 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 97662306a36Sopenharmony_ci kfree(new); 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci return res; 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_get_lock_context); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_civoid nfs_put_lock_context(struct nfs_lock_context *l_ctx) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci struct nfs_open_context *ctx = l_ctx->open_context; 98562306a36Sopenharmony_ci struct inode *inode = d_inode(ctx->dentry); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci if (!refcount_dec_and_lock(&l_ctx->count, &inode->i_lock)) 98862306a36Sopenharmony_ci return; 98962306a36Sopenharmony_ci list_del_rcu(&l_ctx->list); 99062306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 99162306a36Sopenharmony_ci put_nfs_open_context(ctx); 99262306a36Sopenharmony_ci kfree_rcu(l_ctx, rcu_head); 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_put_lock_context); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci/** 99762306a36Sopenharmony_ci * nfs_close_context - Common close_context() routine NFSv2/v3 99862306a36Sopenharmony_ci * @ctx: pointer to context 99962306a36Sopenharmony_ci * @is_sync: is this a synchronous close 100062306a36Sopenharmony_ci * 100162306a36Sopenharmony_ci * Ensure that the attributes are up to date if we're mounted 100262306a36Sopenharmony_ci * with close-to-open semantics and we have cached data that will 100362306a36Sopenharmony_ci * need to be revalidated on open. 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_civoid nfs_close_context(struct nfs_open_context *ctx, int is_sync) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci struct nfs_inode *nfsi; 100862306a36Sopenharmony_ci struct inode *inode; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci if (!(ctx->mode & FMODE_WRITE)) 101162306a36Sopenharmony_ci return; 101262306a36Sopenharmony_ci if (!is_sync) 101362306a36Sopenharmony_ci return; 101462306a36Sopenharmony_ci inode = d_inode(ctx->dentry); 101562306a36Sopenharmony_ci if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) 101662306a36Sopenharmony_ci return; 101762306a36Sopenharmony_ci nfsi = NFS_I(inode); 101862306a36Sopenharmony_ci if (inode->i_mapping->nrpages == 0) 101962306a36Sopenharmony_ci return; 102062306a36Sopenharmony_ci if (nfsi->cache_validity & NFS_INO_INVALID_DATA) 102162306a36Sopenharmony_ci return; 102262306a36Sopenharmony_ci if (!list_empty(&nfsi->open_files)) 102362306a36Sopenharmony_ci return; 102462306a36Sopenharmony_ci if (NFS_SERVER(inode)->flags & NFS_MOUNT_NOCTO) 102562306a36Sopenharmony_ci return; 102662306a36Sopenharmony_ci nfs_revalidate_inode(inode, 102762306a36Sopenharmony_ci NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE); 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_close_context); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistruct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, 103262306a36Sopenharmony_ci fmode_t f_mode, 103362306a36Sopenharmony_ci struct file *filp) 103462306a36Sopenharmony_ci{ 103562306a36Sopenharmony_ci struct nfs_open_context *ctx; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci ctx = kmalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT); 103862306a36Sopenharmony_ci if (!ctx) 103962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 104062306a36Sopenharmony_ci nfs_sb_active(dentry->d_sb); 104162306a36Sopenharmony_ci ctx->dentry = dget(dentry); 104262306a36Sopenharmony_ci if (filp) 104362306a36Sopenharmony_ci ctx->cred = get_cred(filp->f_cred); 104462306a36Sopenharmony_ci else 104562306a36Sopenharmony_ci ctx->cred = get_current_cred(); 104662306a36Sopenharmony_ci rcu_assign_pointer(ctx->ll_cred, NULL); 104762306a36Sopenharmony_ci ctx->state = NULL; 104862306a36Sopenharmony_ci ctx->mode = f_mode; 104962306a36Sopenharmony_ci ctx->flags = 0; 105062306a36Sopenharmony_ci ctx->error = 0; 105162306a36Sopenharmony_ci ctx->flock_owner = (fl_owner_t)filp; 105262306a36Sopenharmony_ci nfs_init_lock_context(&ctx->lock_context); 105362306a36Sopenharmony_ci ctx->lock_context.open_context = ctx; 105462306a36Sopenharmony_ci INIT_LIST_HEAD(&ctx->list); 105562306a36Sopenharmony_ci ctx->mdsthreshold = NULL; 105662306a36Sopenharmony_ci return ctx; 105762306a36Sopenharmony_ci} 105862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(alloc_nfs_open_context); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_cistruct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) 106162306a36Sopenharmony_ci{ 106262306a36Sopenharmony_ci if (ctx != NULL && refcount_inc_not_zero(&ctx->lock_context.count)) 106362306a36Sopenharmony_ci return ctx; 106462306a36Sopenharmony_ci return NULL; 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(get_nfs_open_context); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci struct inode *inode = d_inode(ctx->dentry); 107162306a36Sopenharmony_ci struct super_block *sb = ctx->dentry->d_sb; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (!refcount_dec_and_test(&ctx->lock_context.count)) 107462306a36Sopenharmony_ci return; 107562306a36Sopenharmony_ci if (!list_empty(&ctx->list)) { 107662306a36Sopenharmony_ci spin_lock(&inode->i_lock); 107762306a36Sopenharmony_ci list_del_rcu(&ctx->list); 107862306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci if (inode != NULL) 108162306a36Sopenharmony_ci NFS_PROTO(inode)->close_context(ctx, is_sync); 108262306a36Sopenharmony_ci put_cred(ctx->cred); 108362306a36Sopenharmony_ci dput(ctx->dentry); 108462306a36Sopenharmony_ci nfs_sb_deactive(sb); 108562306a36Sopenharmony_ci put_rpccred(rcu_dereference_protected(ctx->ll_cred, 1)); 108662306a36Sopenharmony_ci kfree(ctx->mdsthreshold); 108762306a36Sopenharmony_ci kfree_rcu(ctx, rcu_head); 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_civoid put_nfs_open_context(struct nfs_open_context *ctx) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci __put_nfs_open_context(ctx, 0); 109362306a36Sopenharmony_ci} 109462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(put_nfs_open_context); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic void put_nfs_open_context_sync(struct nfs_open_context *ctx) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci __put_nfs_open_context(ctx, 1); 109962306a36Sopenharmony_ci} 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci/* 110262306a36Sopenharmony_ci * Ensure that mmap has a recent RPC credential for use when writing out 110362306a36Sopenharmony_ci * shared pages 110462306a36Sopenharmony_ci */ 110562306a36Sopenharmony_civoid nfs_inode_attach_open_context(struct nfs_open_context *ctx) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci struct inode *inode = d_inode(ctx->dentry); 110862306a36Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci spin_lock(&inode->i_lock); 111162306a36Sopenharmony_ci if (list_empty(&nfsi->open_files) && 111262306a36Sopenharmony_ci nfs_ooo_test(nfsi)) 111362306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA | 111462306a36Sopenharmony_ci NFS_INO_REVAL_FORCED); 111562306a36Sopenharmony_ci list_add_tail_rcu(&ctx->list, &nfsi->open_files); 111662306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_inode_attach_open_context); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_civoid nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) 112162306a36Sopenharmony_ci{ 112262306a36Sopenharmony_ci filp->private_data = get_nfs_open_context(ctx); 112362306a36Sopenharmony_ci set_bit(NFS_CONTEXT_FILE_OPEN, &ctx->flags); 112462306a36Sopenharmony_ci if (list_empty(&ctx->list)) 112562306a36Sopenharmony_ci nfs_inode_attach_open_context(ctx); 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_file_set_open_context); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci/* 113062306a36Sopenharmony_ci * Given an inode, search for an open context with the desired characteristics 113162306a36Sopenharmony_ci */ 113262306a36Sopenharmony_cistruct nfs_open_context *nfs_find_open_context(struct inode *inode, const struct cred *cred, fmode_t mode) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 113562306a36Sopenharmony_ci struct nfs_open_context *pos, *ctx = NULL; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci rcu_read_lock(); 113862306a36Sopenharmony_ci list_for_each_entry_rcu(pos, &nfsi->open_files, list) { 113962306a36Sopenharmony_ci if (cred != NULL && cred_fscmp(pos->cred, cred) != 0) 114062306a36Sopenharmony_ci continue; 114162306a36Sopenharmony_ci if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode) 114262306a36Sopenharmony_ci continue; 114362306a36Sopenharmony_ci if (!test_bit(NFS_CONTEXT_FILE_OPEN, &pos->flags)) 114462306a36Sopenharmony_ci continue; 114562306a36Sopenharmony_ci ctx = get_nfs_open_context(pos); 114662306a36Sopenharmony_ci if (ctx) 114762306a36Sopenharmony_ci break; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci rcu_read_unlock(); 115062306a36Sopenharmony_ci return ctx; 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_civoid nfs_file_clear_open_context(struct file *filp) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci struct nfs_open_context *ctx = nfs_file_open_context(filp); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci if (ctx) { 115862306a36Sopenharmony_ci struct inode *inode = d_inode(ctx->dentry); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci clear_bit(NFS_CONTEXT_FILE_OPEN, &ctx->flags); 116162306a36Sopenharmony_ci /* 116262306a36Sopenharmony_ci * We fatal error on write before. Try to writeback 116362306a36Sopenharmony_ci * every page again. 116462306a36Sopenharmony_ci */ 116562306a36Sopenharmony_ci if (ctx->error < 0) 116662306a36Sopenharmony_ci invalidate_inode_pages2(inode->i_mapping); 116762306a36Sopenharmony_ci filp->private_data = NULL; 116862306a36Sopenharmony_ci put_nfs_open_context_sync(ctx); 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci} 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci/* 117362306a36Sopenharmony_ci * These allocate and release file read/write context information. 117462306a36Sopenharmony_ci */ 117562306a36Sopenharmony_ciint nfs_open(struct inode *inode, struct file *filp) 117662306a36Sopenharmony_ci{ 117762306a36Sopenharmony_ci struct nfs_open_context *ctx; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci ctx = alloc_nfs_open_context(file_dentry(filp), 118062306a36Sopenharmony_ci flags_to_mode(filp->f_flags), filp); 118162306a36Sopenharmony_ci if (IS_ERR(ctx)) 118262306a36Sopenharmony_ci return PTR_ERR(ctx); 118362306a36Sopenharmony_ci nfs_file_set_open_context(filp, ctx); 118462306a36Sopenharmony_ci put_nfs_open_context(ctx); 118562306a36Sopenharmony_ci nfs_fscache_open_file(inode, filp); 118662306a36Sopenharmony_ci return 0; 118762306a36Sopenharmony_ci} 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci/* 119062306a36Sopenharmony_ci * This function is called whenever some part of NFS notices that 119162306a36Sopenharmony_ci * the cached attributes have to be refreshed. 119262306a36Sopenharmony_ci */ 119362306a36Sopenharmony_ciint 119462306a36Sopenharmony_ci__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) 119562306a36Sopenharmony_ci{ 119662306a36Sopenharmony_ci int status = -ESTALE; 119762306a36Sopenharmony_ci struct nfs_fattr *fattr = NULL; 119862306a36Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci dfprintk(PAGECACHE, "NFS: revalidating (%s/%Lu)\n", 120162306a36Sopenharmony_ci inode->i_sb->s_id, (unsigned long long)NFS_FILEID(inode)); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci trace_nfs_revalidate_inode_enter(inode); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (is_bad_inode(inode)) 120662306a36Sopenharmony_ci goto out; 120762306a36Sopenharmony_ci if (NFS_STALE(inode)) 120862306a36Sopenharmony_ci goto out; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci /* pNFS: Attributes aren't updated until we layoutcommit */ 121162306a36Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 121262306a36Sopenharmony_ci status = pnfs_sync_inode(inode, false); 121362306a36Sopenharmony_ci if (status) 121462306a36Sopenharmony_ci goto out; 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci status = -ENOMEM; 121862306a36Sopenharmony_ci fattr = nfs_alloc_fattr_with_label(NFS_SERVER(inode)); 121962306a36Sopenharmony_ci if (fattr == NULL) 122062306a36Sopenharmony_ci goto out; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, inode); 122562306a36Sopenharmony_ci if (status != 0) { 122662306a36Sopenharmony_ci dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) getattr failed, error=%d\n", 122762306a36Sopenharmony_ci inode->i_sb->s_id, 122862306a36Sopenharmony_ci (unsigned long long)NFS_FILEID(inode), status); 122962306a36Sopenharmony_ci switch (status) { 123062306a36Sopenharmony_ci case -ETIMEDOUT: 123162306a36Sopenharmony_ci /* A soft timeout occurred. Use cached information? */ 123262306a36Sopenharmony_ci if (server->flags & NFS_MOUNT_SOFTREVAL) 123362306a36Sopenharmony_ci status = 0; 123462306a36Sopenharmony_ci break; 123562306a36Sopenharmony_ci case -ESTALE: 123662306a36Sopenharmony_ci if (!S_ISDIR(inode->i_mode)) 123762306a36Sopenharmony_ci nfs_set_inode_stale(inode); 123862306a36Sopenharmony_ci else 123962306a36Sopenharmony_ci nfs_zap_caches(inode); 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci goto out; 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci status = nfs_refresh_inode(inode, fattr); 124562306a36Sopenharmony_ci if (status) { 124662306a36Sopenharmony_ci dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) refresh failed, error=%d\n", 124762306a36Sopenharmony_ci inode->i_sb->s_id, 124862306a36Sopenharmony_ci (unsigned long long)NFS_FILEID(inode), status); 124962306a36Sopenharmony_ci goto out; 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci if (nfsi->cache_validity & NFS_INO_INVALID_ACL) 125362306a36Sopenharmony_ci nfs_zap_acl_cache(inode); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci nfs_setsecurity(inode, fattr); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci dfprintk(PAGECACHE, "NFS: (%s/%Lu) revalidation complete\n", 125862306a36Sopenharmony_ci inode->i_sb->s_id, 125962306a36Sopenharmony_ci (unsigned long long)NFS_FILEID(inode)); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ciout: 126262306a36Sopenharmony_ci nfs_free_fattr(fattr); 126362306a36Sopenharmony_ci trace_nfs_revalidate_inode_exit(inode, status); 126462306a36Sopenharmony_ci return status; 126562306a36Sopenharmony_ci} 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ciint nfs_attribute_cache_expired(struct inode *inode) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci if (nfs_have_delegated_attributes(inode)) 127062306a36Sopenharmony_ci return 0; 127162306a36Sopenharmony_ci return nfs_attribute_timeout(inode); 127262306a36Sopenharmony_ci} 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci/** 127562306a36Sopenharmony_ci * nfs_revalidate_inode - Revalidate the inode attributes 127662306a36Sopenharmony_ci * @inode: pointer to inode struct 127762306a36Sopenharmony_ci * @flags: cache flags to check 127862306a36Sopenharmony_ci * 127962306a36Sopenharmony_ci * Updates inode attribute information by retrieving the data from the server. 128062306a36Sopenharmony_ci */ 128162306a36Sopenharmony_ciint nfs_revalidate_inode(struct inode *inode, unsigned long flags) 128262306a36Sopenharmony_ci{ 128362306a36Sopenharmony_ci if (!nfs_check_cache_invalid(inode, flags)) 128462306a36Sopenharmony_ci return NFS_STALE(inode) ? -ESTALE : 0; 128562306a36Sopenharmony_ci return __nfs_revalidate_inode(NFS_SERVER(inode), inode); 128662306a36Sopenharmony_ci} 128762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_revalidate_inode); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_cistatic int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) 129062306a36Sopenharmony_ci{ 129162306a36Sopenharmony_ci int ret; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci nfs_fscache_invalidate(inode, 0); 129462306a36Sopenharmony_ci if (mapping->nrpages != 0) { 129562306a36Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 129662306a36Sopenharmony_ci ret = nfs_sync_mapping(mapping); 129762306a36Sopenharmony_ci if (ret < 0) 129862306a36Sopenharmony_ci return ret; 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci ret = invalidate_inode_pages2(mapping); 130162306a36Sopenharmony_ci if (ret < 0) 130262306a36Sopenharmony_ci return ret; 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci dfprintk(PAGECACHE, "NFS: (%s/%Lu) data cache invalidated\n", 130762306a36Sopenharmony_ci inode->i_sb->s_id, 130862306a36Sopenharmony_ci (unsigned long long)NFS_FILEID(inode)); 130962306a36Sopenharmony_ci return 0; 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci/** 131362306a36Sopenharmony_ci * nfs_clear_invalid_mapping - Conditionally clear a mapping 131462306a36Sopenharmony_ci * @mapping: pointer to mapping 131562306a36Sopenharmony_ci * 131662306a36Sopenharmony_ci * If the NFS_INO_INVALID_DATA inode flag is set, clear the mapping. 131762306a36Sopenharmony_ci */ 131862306a36Sopenharmony_ciint nfs_clear_invalid_mapping(struct address_space *mapping) 131962306a36Sopenharmony_ci{ 132062306a36Sopenharmony_ci struct inode *inode = mapping->host; 132162306a36Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 132262306a36Sopenharmony_ci unsigned long *bitlock = &nfsi->flags; 132362306a36Sopenharmony_ci int ret = 0; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci /* 132662306a36Sopenharmony_ci * We must clear NFS_INO_INVALID_DATA first to ensure that 132762306a36Sopenharmony_ci * invalidations that come in while we're shooting down the mappings 132862306a36Sopenharmony_ci * are respected. But, that leaves a race window where one revalidator 132962306a36Sopenharmony_ci * can clear the flag, and then another checks it before the mapping 133062306a36Sopenharmony_ci * gets invalidated. Fix that by serializing access to this part of 133162306a36Sopenharmony_ci * the function. 133262306a36Sopenharmony_ci * 133362306a36Sopenharmony_ci * At the same time, we need to allow other tasks to see whether we 133462306a36Sopenharmony_ci * might be in the middle of invalidating the pages, so we only set 133562306a36Sopenharmony_ci * the bit lock here if it looks like we're going to be doing that. 133662306a36Sopenharmony_ci */ 133762306a36Sopenharmony_ci for (;;) { 133862306a36Sopenharmony_ci ret = wait_on_bit_action(bitlock, NFS_INO_INVALIDATING, 133962306a36Sopenharmony_ci nfs_wait_bit_killable, 134062306a36Sopenharmony_ci TASK_KILLABLE|TASK_FREEZABLE_UNSAFE); 134162306a36Sopenharmony_ci if (ret) 134262306a36Sopenharmony_ci goto out; 134362306a36Sopenharmony_ci spin_lock(&inode->i_lock); 134462306a36Sopenharmony_ci if (test_bit(NFS_INO_INVALIDATING, bitlock)) { 134562306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 134662306a36Sopenharmony_ci continue; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci if (nfsi->cache_validity & NFS_INO_INVALID_DATA) 134962306a36Sopenharmony_ci break; 135062306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 135162306a36Sopenharmony_ci goto out; 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci set_bit(NFS_INO_INVALIDATING, bitlock); 135562306a36Sopenharmony_ci smp_wmb(); 135662306a36Sopenharmony_ci nfsi->cache_validity &= ~NFS_INO_INVALID_DATA; 135762306a36Sopenharmony_ci nfs_ooo_clear(nfsi); 135862306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 135962306a36Sopenharmony_ci trace_nfs_invalidate_mapping_enter(inode); 136062306a36Sopenharmony_ci ret = nfs_invalidate_mapping(inode, mapping); 136162306a36Sopenharmony_ci trace_nfs_invalidate_mapping_exit(inode, ret); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci clear_bit_unlock(NFS_INO_INVALIDATING, bitlock); 136462306a36Sopenharmony_ci smp_mb__after_atomic(); 136562306a36Sopenharmony_ci wake_up_bit(bitlock, NFS_INO_INVALIDATING); 136662306a36Sopenharmony_ciout: 136762306a36Sopenharmony_ci return ret; 136862306a36Sopenharmony_ci} 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_cibool nfs_mapping_need_revalidate_inode(struct inode *inode) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci return nfs_check_cache_invalid(inode, NFS_INO_INVALID_CHANGE) || 137362306a36Sopenharmony_ci NFS_STALE(inode); 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ciint nfs_revalidate_mapping_rcu(struct inode *inode) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 137962306a36Sopenharmony_ci unsigned long *bitlock = &nfsi->flags; 138062306a36Sopenharmony_ci int ret = 0; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci if (IS_SWAPFILE(inode)) 138362306a36Sopenharmony_ci goto out; 138462306a36Sopenharmony_ci if (nfs_mapping_need_revalidate_inode(inode)) { 138562306a36Sopenharmony_ci ret = -ECHILD; 138662306a36Sopenharmony_ci goto out; 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci spin_lock(&inode->i_lock); 138962306a36Sopenharmony_ci if (test_bit(NFS_INO_INVALIDATING, bitlock) || 139062306a36Sopenharmony_ci (nfsi->cache_validity & NFS_INO_INVALID_DATA)) 139162306a36Sopenharmony_ci ret = -ECHILD; 139262306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 139362306a36Sopenharmony_ciout: 139462306a36Sopenharmony_ci return ret; 139562306a36Sopenharmony_ci} 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci/** 139862306a36Sopenharmony_ci * nfs_revalidate_mapping - Revalidate the pagecache 139962306a36Sopenharmony_ci * @inode: pointer to host inode 140062306a36Sopenharmony_ci * @mapping: pointer to mapping 140162306a36Sopenharmony_ci */ 140262306a36Sopenharmony_ciint nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) 140362306a36Sopenharmony_ci{ 140462306a36Sopenharmony_ci /* swapfiles are not supposed to be shared. */ 140562306a36Sopenharmony_ci if (IS_SWAPFILE(inode)) 140662306a36Sopenharmony_ci return 0; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci if (nfs_mapping_need_revalidate_inode(inode)) { 140962306a36Sopenharmony_ci int ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); 141062306a36Sopenharmony_ci if (ret < 0) 141162306a36Sopenharmony_ci return ret; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci return nfs_clear_invalid_mapping(mapping); 141562306a36Sopenharmony_ci} 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_cistatic bool nfs_file_has_writers(struct nfs_inode *nfsi) 141862306a36Sopenharmony_ci{ 141962306a36Sopenharmony_ci struct inode *inode = &nfsi->vfs_inode; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci if (!S_ISREG(inode->i_mode)) 142262306a36Sopenharmony_ci return false; 142362306a36Sopenharmony_ci if (list_empty(&nfsi->open_files)) 142462306a36Sopenharmony_ci return false; 142562306a36Sopenharmony_ci return inode_is_open_for_write(inode); 142662306a36Sopenharmony_ci} 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_cistatic bool nfs_file_has_buffered_writers(struct nfs_inode *nfsi) 142962306a36Sopenharmony_ci{ 143062306a36Sopenharmony_ci return nfs_file_has_writers(nfsi) && nfs_file_io_is_buffered(nfsi); 143162306a36Sopenharmony_ci} 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_cistatic void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) 143462306a36Sopenharmony_ci{ 143562306a36Sopenharmony_ci struct timespec64 ts; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE) 143862306a36Sopenharmony_ci && (fattr->valid & NFS_ATTR_FATTR_CHANGE) 143962306a36Sopenharmony_ci && inode_eq_iversion_raw(inode, fattr->pre_change_attr)) { 144062306a36Sopenharmony_ci inode_set_iversion_raw(inode, fattr->change_attr); 144162306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 144262306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA); 144362306a36Sopenharmony_ci else if (nfs_server_capable(inode, NFS_CAP_XATTR)) 144462306a36Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_XATTR); 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci /* If we have atomic WCC data, we may update some attributes */ 144762306a36Sopenharmony_ci ts = inode_get_ctime(inode); 144862306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME) 144962306a36Sopenharmony_ci && (fattr->valid & NFS_ATTR_FATTR_CTIME) 145062306a36Sopenharmony_ci && timespec64_equal(&ts, &fattr->pre_ctime)) { 145162306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, fattr->ctime); 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci ts = inode->i_mtime; 145562306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME) 145662306a36Sopenharmony_ci && (fattr->valid & NFS_ATTR_FATTR_MTIME) 145762306a36Sopenharmony_ci && timespec64_equal(&ts, &fattr->pre_mtime)) { 145862306a36Sopenharmony_ci inode->i_mtime = fattr->mtime; 145962306a36Sopenharmony_ci } 146062306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE) 146162306a36Sopenharmony_ci && (fattr->valid & NFS_ATTR_FATTR_SIZE) 146262306a36Sopenharmony_ci && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size) 146362306a36Sopenharmony_ci && !nfs_have_writebacks(inode)) { 146462306a36Sopenharmony_ci trace_nfs_size_wcc(inode, fattr->size); 146562306a36Sopenharmony_ci i_size_write(inode, nfs_size_to_loff_t(fattr->size)); 146662306a36Sopenharmony_ci } 146762306a36Sopenharmony_ci} 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci/** 147062306a36Sopenharmony_ci * nfs_check_inode_attributes - verify consistency of the inode attribute cache 147162306a36Sopenharmony_ci * @inode: pointer to inode 147262306a36Sopenharmony_ci * @fattr: updated attributes 147362306a36Sopenharmony_ci * 147462306a36Sopenharmony_ci * Verifies the attribute cache. If we have just changed the attributes, 147562306a36Sopenharmony_ci * so that fattr carries weak cache consistency data, then it may 147662306a36Sopenharmony_ci * also update the ctime/mtime/change_attribute. 147762306a36Sopenharmony_ci */ 147862306a36Sopenharmony_cistatic int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fattr) 147962306a36Sopenharmony_ci{ 148062306a36Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 148162306a36Sopenharmony_ci loff_t cur_size, new_isize; 148262306a36Sopenharmony_ci unsigned long invalid = 0; 148362306a36Sopenharmony_ci struct timespec64 ts; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) 148662306a36Sopenharmony_ci return 0; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci if (!(fattr->valid & NFS_ATTR_FATTR_FILEID)) { 148962306a36Sopenharmony_ci /* Only a mounted-on-fileid? Just exit */ 149062306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) 149162306a36Sopenharmony_ci return 0; 149262306a36Sopenharmony_ci /* Has the inode gone and changed behind our back? */ 149362306a36Sopenharmony_ci } else if (nfsi->fileid != fattr->fileid) { 149462306a36Sopenharmony_ci /* Is this perhaps the mounted-on fileid? */ 149562306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) && 149662306a36Sopenharmony_ci nfsi->fileid == fattr->mounted_on_fileid) 149762306a36Sopenharmony_ci return 0; 149862306a36Sopenharmony_ci return -ESTALE; 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && inode_wrong_type(inode, fattr->mode)) 150162306a36Sopenharmony_ci return -ESTALE; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci if (!nfs_file_has_buffered_writers(nfsi)) { 150562306a36Sopenharmony_ci /* Verify a few of the more important attributes */ 150662306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && !inode_eq_iversion_raw(inode, fattr->change_attr)) 150762306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_CHANGE; 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci ts = inode->i_mtime; 151062306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec64_equal(&ts, &fattr->mtime)) 151162306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_MTIME; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci ts = inode_get_ctime(inode); 151462306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_CTIME) && !timespec64_equal(&ts, &fattr->ctime)) 151562306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_CTIME; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_SIZE) { 151862306a36Sopenharmony_ci cur_size = i_size_read(inode); 151962306a36Sopenharmony_ci new_isize = nfs_size_to_loff_t(fattr->size); 152062306a36Sopenharmony_ci if (cur_size != new_isize) 152162306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_SIZE; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci /* Have any file permissions changed? */ 152662306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) 152762306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_MODE; 152862306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && !uid_eq(inode->i_uid, fattr->uid)) 152962306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_OTHER; 153062306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && !gid_eq(inode->i_gid, fattr->gid)) 153162306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_OTHER; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci /* Has the link count changed? */ 153462306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_NLINK) && inode->i_nlink != fattr->nlink) 153562306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_NLINK; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci ts = inode->i_atime; 153862306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_ATIME) && !timespec64_equal(&ts, &fattr->atime)) 153962306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_ATIME; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci if (invalid != 0) 154262306a36Sopenharmony_ci nfs_set_cache_invalid(inode, invalid); 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci nfsi->read_cache_jiffies = fattr->time_start; 154562306a36Sopenharmony_ci return 0; 154662306a36Sopenharmony_ci} 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_cistatic atomic_long_t nfs_attr_generation_counter; 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_cistatic unsigned long nfs_read_attr_generation_counter(void) 155162306a36Sopenharmony_ci{ 155262306a36Sopenharmony_ci return atomic_long_read(&nfs_attr_generation_counter); 155362306a36Sopenharmony_ci} 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ciunsigned long nfs_inc_attr_generation_counter(void) 155662306a36Sopenharmony_ci{ 155762306a36Sopenharmony_ci return atomic_long_inc_return(&nfs_attr_generation_counter); 155862306a36Sopenharmony_ci} 155962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_inc_attr_generation_counter); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_civoid nfs_fattr_init(struct nfs_fattr *fattr) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci fattr->valid = 0; 156462306a36Sopenharmony_ci fattr->time_start = jiffies; 156562306a36Sopenharmony_ci fattr->gencount = nfs_inc_attr_generation_counter(); 156662306a36Sopenharmony_ci fattr->owner_name = NULL; 156762306a36Sopenharmony_ci fattr->group_name = NULL; 156862306a36Sopenharmony_ci} 156962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_fattr_init); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci/** 157262306a36Sopenharmony_ci * nfs_fattr_set_barrier 157362306a36Sopenharmony_ci * @fattr: attributes 157462306a36Sopenharmony_ci * 157562306a36Sopenharmony_ci * Used to set a barrier after an attribute was updated. This 157662306a36Sopenharmony_ci * barrier ensures that older attributes from RPC calls that may 157762306a36Sopenharmony_ci * have raced with our update cannot clobber these new values. 157862306a36Sopenharmony_ci * Note that you are still responsible for ensuring that other 157962306a36Sopenharmony_ci * operations which change the attribute on the server do not 158062306a36Sopenharmony_ci * collide. 158162306a36Sopenharmony_ci */ 158262306a36Sopenharmony_civoid nfs_fattr_set_barrier(struct nfs_fattr *fattr) 158362306a36Sopenharmony_ci{ 158462306a36Sopenharmony_ci fattr->gencount = nfs_inc_attr_generation_counter(); 158562306a36Sopenharmony_ci} 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_cistruct nfs_fattr *nfs_alloc_fattr(void) 158862306a36Sopenharmony_ci{ 158962306a36Sopenharmony_ci struct nfs_fattr *fattr; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci fattr = kmalloc(sizeof(*fattr), GFP_KERNEL); 159262306a36Sopenharmony_ci if (fattr != NULL) { 159362306a36Sopenharmony_ci nfs_fattr_init(fattr); 159462306a36Sopenharmony_ci fattr->label = NULL; 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci return fattr; 159762306a36Sopenharmony_ci} 159862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_alloc_fattr); 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_cistruct nfs_fattr *nfs_alloc_fattr_with_label(struct nfs_server *server) 160162306a36Sopenharmony_ci{ 160262306a36Sopenharmony_ci struct nfs_fattr *fattr = nfs_alloc_fattr(); 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci if (!fattr) 160562306a36Sopenharmony_ci return NULL; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci fattr->label = nfs4_label_alloc(server, GFP_KERNEL); 160862306a36Sopenharmony_ci if (IS_ERR(fattr->label)) { 160962306a36Sopenharmony_ci kfree(fattr); 161062306a36Sopenharmony_ci return NULL; 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci return fattr; 161462306a36Sopenharmony_ci} 161562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_alloc_fattr_with_label); 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_cistruct nfs_fh *nfs_alloc_fhandle(void) 161862306a36Sopenharmony_ci{ 161962306a36Sopenharmony_ci struct nfs_fh *fh; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci fh = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL); 162262306a36Sopenharmony_ci if (fh != NULL) 162362306a36Sopenharmony_ci fh->size = 0; 162462306a36Sopenharmony_ci return fh; 162562306a36Sopenharmony_ci} 162662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_alloc_fhandle); 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci#ifdef NFS_DEBUG 162962306a36Sopenharmony_ci/* 163062306a36Sopenharmony_ci * _nfs_display_fhandle_hash - calculate the crc32 hash for the filehandle 163162306a36Sopenharmony_ci * in the same way that wireshark does 163262306a36Sopenharmony_ci * 163362306a36Sopenharmony_ci * @fh: file handle 163462306a36Sopenharmony_ci * 163562306a36Sopenharmony_ci * For debugging only. 163662306a36Sopenharmony_ci */ 163762306a36Sopenharmony_ciu32 _nfs_display_fhandle_hash(const struct nfs_fh *fh) 163862306a36Sopenharmony_ci{ 163962306a36Sopenharmony_ci /* wireshark uses 32-bit AUTODIN crc and does a bitwise 164062306a36Sopenharmony_ci * not on the result */ 164162306a36Sopenharmony_ci return nfs_fhandle_hash(fh); 164262306a36Sopenharmony_ci} 164362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(_nfs_display_fhandle_hash); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci/* 164662306a36Sopenharmony_ci * _nfs_display_fhandle - display an NFS file handle on the console 164762306a36Sopenharmony_ci * 164862306a36Sopenharmony_ci * @fh: file handle to display 164962306a36Sopenharmony_ci * @caption: display caption 165062306a36Sopenharmony_ci * 165162306a36Sopenharmony_ci * For debugging only. 165262306a36Sopenharmony_ci */ 165362306a36Sopenharmony_civoid _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption) 165462306a36Sopenharmony_ci{ 165562306a36Sopenharmony_ci unsigned short i; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci if (fh == NULL || fh->size == 0) { 165862306a36Sopenharmony_ci printk(KERN_DEFAULT "%s at %p is empty\n", caption, fh); 165962306a36Sopenharmony_ci return; 166062306a36Sopenharmony_ci } 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci printk(KERN_DEFAULT "%s at %p is %u bytes, crc: 0x%08x:\n", 166362306a36Sopenharmony_ci caption, fh, fh->size, _nfs_display_fhandle_hash(fh)); 166462306a36Sopenharmony_ci for (i = 0; i < fh->size; i += 16) { 166562306a36Sopenharmony_ci __be32 *pos = (__be32 *)&fh->data[i]; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci switch ((fh->size - i - 1) >> 2) { 166862306a36Sopenharmony_ci case 0: 166962306a36Sopenharmony_ci printk(KERN_DEFAULT " %08x\n", 167062306a36Sopenharmony_ci be32_to_cpup(pos)); 167162306a36Sopenharmony_ci break; 167262306a36Sopenharmony_ci case 1: 167362306a36Sopenharmony_ci printk(KERN_DEFAULT " %08x %08x\n", 167462306a36Sopenharmony_ci be32_to_cpup(pos), be32_to_cpup(pos + 1)); 167562306a36Sopenharmony_ci break; 167662306a36Sopenharmony_ci case 2: 167762306a36Sopenharmony_ci printk(KERN_DEFAULT " %08x %08x %08x\n", 167862306a36Sopenharmony_ci be32_to_cpup(pos), be32_to_cpup(pos + 1), 167962306a36Sopenharmony_ci be32_to_cpup(pos + 2)); 168062306a36Sopenharmony_ci break; 168162306a36Sopenharmony_ci default: 168262306a36Sopenharmony_ci printk(KERN_DEFAULT " %08x %08x %08x %08x\n", 168362306a36Sopenharmony_ci be32_to_cpup(pos), be32_to_cpup(pos + 1), 168462306a36Sopenharmony_ci be32_to_cpup(pos + 2), be32_to_cpup(pos + 3)); 168562306a36Sopenharmony_ci } 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci} 168862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(_nfs_display_fhandle); 168962306a36Sopenharmony_ci#endif 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci/** 169262306a36Sopenharmony_ci * nfs_inode_attrs_cmp_generic - compare attributes 169362306a36Sopenharmony_ci * @fattr: attributes 169462306a36Sopenharmony_ci * @inode: pointer to inode 169562306a36Sopenharmony_ci * 169662306a36Sopenharmony_ci * Attempt to divine whether or not an RPC call reply carrying stale 169762306a36Sopenharmony_ci * attributes got scheduled after another call carrying updated ones. 169862306a36Sopenharmony_ci * Note also the check for wraparound of 'attr_gencount' 169962306a36Sopenharmony_ci * 170062306a36Sopenharmony_ci * The function returns '1' if it thinks the attributes in @fattr are 170162306a36Sopenharmony_ci * more recent than the ones cached in @inode. Otherwise it returns 170262306a36Sopenharmony_ci * the value '0'. 170362306a36Sopenharmony_ci */ 170462306a36Sopenharmony_cistatic int nfs_inode_attrs_cmp_generic(const struct nfs_fattr *fattr, 170562306a36Sopenharmony_ci const struct inode *inode) 170662306a36Sopenharmony_ci{ 170762306a36Sopenharmony_ci unsigned long attr_gencount = NFS_I(inode)->attr_gencount; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci return (long)(fattr->gencount - attr_gencount) > 0 || 171062306a36Sopenharmony_ci (long)(attr_gencount - nfs_read_attr_generation_counter()) > 0; 171162306a36Sopenharmony_ci} 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci/** 171462306a36Sopenharmony_ci * nfs_inode_attrs_cmp_monotonic - compare attributes 171562306a36Sopenharmony_ci * @fattr: attributes 171662306a36Sopenharmony_ci * @inode: pointer to inode 171762306a36Sopenharmony_ci * 171862306a36Sopenharmony_ci * Attempt to divine whether or not an RPC call reply carrying stale 171962306a36Sopenharmony_ci * attributes got scheduled after another call carrying updated ones. 172062306a36Sopenharmony_ci * 172162306a36Sopenharmony_ci * We assume that the server observes monotonic semantics for 172262306a36Sopenharmony_ci * the change attribute, so a larger value means that the attributes in 172362306a36Sopenharmony_ci * @fattr are more recent, in which case the function returns the 172462306a36Sopenharmony_ci * value '1'. 172562306a36Sopenharmony_ci * A return value of '0' indicates no measurable change 172662306a36Sopenharmony_ci * A return value of '-1' means that the attributes in @inode are 172762306a36Sopenharmony_ci * more recent. 172862306a36Sopenharmony_ci */ 172962306a36Sopenharmony_cistatic int nfs_inode_attrs_cmp_monotonic(const struct nfs_fattr *fattr, 173062306a36Sopenharmony_ci const struct inode *inode) 173162306a36Sopenharmony_ci{ 173262306a36Sopenharmony_ci s64 diff = fattr->change_attr - inode_peek_iversion_raw(inode); 173362306a36Sopenharmony_ci if (diff > 0) 173462306a36Sopenharmony_ci return 1; 173562306a36Sopenharmony_ci return diff == 0 ? 0 : -1; 173662306a36Sopenharmony_ci} 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci/** 173962306a36Sopenharmony_ci * nfs_inode_attrs_cmp_strict_monotonic - compare attributes 174062306a36Sopenharmony_ci * @fattr: attributes 174162306a36Sopenharmony_ci * @inode: pointer to inode 174262306a36Sopenharmony_ci * 174362306a36Sopenharmony_ci * Attempt to divine whether or not an RPC call reply carrying stale 174462306a36Sopenharmony_ci * attributes got scheduled after another call carrying updated ones. 174562306a36Sopenharmony_ci * 174662306a36Sopenharmony_ci * We assume that the server observes strictly monotonic semantics for 174762306a36Sopenharmony_ci * the change attribute, so a larger value means that the attributes in 174862306a36Sopenharmony_ci * @fattr are more recent, in which case the function returns the 174962306a36Sopenharmony_ci * value '1'. 175062306a36Sopenharmony_ci * A return value of '-1' means that the attributes in @inode are 175162306a36Sopenharmony_ci * more recent or unchanged. 175262306a36Sopenharmony_ci */ 175362306a36Sopenharmony_cistatic int nfs_inode_attrs_cmp_strict_monotonic(const struct nfs_fattr *fattr, 175462306a36Sopenharmony_ci const struct inode *inode) 175562306a36Sopenharmony_ci{ 175662306a36Sopenharmony_ci return nfs_inode_attrs_cmp_monotonic(fattr, inode) > 0 ? 1 : -1; 175762306a36Sopenharmony_ci} 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci/** 176062306a36Sopenharmony_ci * nfs_inode_attrs_cmp - compare attributes 176162306a36Sopenharmony_ci * @fattr: attributes 176262306a36Sopenharmony_ci * @inode: pointer to inode 176362306a36Sopenharmony_ci * 176462306a36Sopenharmony_ci * This function returns '1' if it thinks the attributes in @fattr are 176562306a36Sopenharmony_ci * more recent than the ones cached in @inode. It returns '-1' if 176662306a36Sopenharmony_ci * the attributes in @inode are more recent than the ones in @fattr, 176762306a36Sopenharmony_ci * and it returns 0 if not sure. 176862306a36Sopenharmony_ci */ 176962306a36Sopenharmony_cistatic int nfs_inode_attrs_cmp(const struct nfs_fattr *fattr, 177062306a36Sopenharmony_ci const struct inode *inode) 177162306a36Sopenharmony_ci{ 177262306a36Sopenharmony_ci if (nfs_inode_attrs_cmp_generic(fattr, inode) > 0) 177362306a36Sopenharmony_ci return 1; 177462306a36Sopenharmony_ci switch (NFS_SERVER(inode)->change_attr_type) { 177562306a36Sopenharmony_ci case NFS4_CHANGE_TYPE_IS_UNDEFINED: 177662306a36Sopenharmony_ci break; 177762306a36Sopenharmony_ci case NFS4_CHANGE_TYPE_IS_TIME_METADATA: 177862306a36Sopenharmony_ci if (!(fattr->valid & NFS_ATTR_FATTR_CHANGE)) 177962306a36Sopenharmony_ci break; 178062306a36Sopenharmony_ci return nfs_inode_attrs_cmp_monotonic(fattr, inode); 178162306a36Sopenharmony_ci default: 178262306a36Sopenharmony_ci if (!(fattr->valid & NFS_ATTR_FATTR_CHANGE)) 178362306a36Sopenharmony_ci break; 178462306a36Sopenharmony_ci return nfs_inode_attrs_cmp_strict_monotonic(fattr, inode); 178562306a36Sopenharmony_ci } 178662306a36Sopenharmony_ci return 0; 178762306a36Sopenharmony_ci} 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci/** 179062306a36Sopenharmony_ci * nfs_inode_finish_partial_attr_update - complete a previous inode update 179162306a36Sopenharmony_ci * @fattr: attributes 179262306a36Sopenharmony_ci * @inode: pointer to inode 179362306a36Sopenharmony_ci * 179462306a36Sopenharmony_ci * Returns '1' if the last attribute update left the inode cached 179562306a36Sopenharmony_ci * attributes in a partially unrevalidated state, and @fattr 179662306a36Sopenharmony_ci * matches the change attribute of that partial update. 179762306a36Sopenharmony_ci * Otherwise returns '0'. 179862306a36Sopenharmony_ci */ 179962306a36Sopenharmony_cistatic int nfs_inode_finish_partial_attr_update(const struct nfs_fattr *fattr, 180062306a36Sopenharmony_ci const struct inode *inode) 180162306a36Sopenharmony_ci{ 180262306a36Sopenharmony_ci const unsigned long check_valid = 180362306a36Sopenharmony_ci NFS_INO_INVALID_ATIME | NFS_INO_INVALID_CTIME | 180462306a36Sopenharmony_ci NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE | 180562306a36Sopenharmony_ci NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_OTHER | 180662306a36Sopenharmony_ci NFS_INO_INVALID_NLINK; 180762306a36Sopenharmony_ci unsigned long cache_validity = NFS_I(inode)->cache_validity; 180862306a36Sopenharmony_ci enum nfs4_change_attr_type ctype = NFS_SERVER(inode)->change_attr_type; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci if (ctype != NFS4_CHANGE_TYPE_IS_UNDEFINED && 181162306a36Sopenharmony_ci !(cache_validity & NFS_INO_INVALID_CHANGE) && 181262306a36Sopenharmony_ci (cache_validity & check_valid) != 0 && 181362306a36Sopenharmony_ci (fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && 181462306a36Sopenharmony_ci nfs_inode_attrs_cmp_monotonic(fattr, inode) == 0) 181562306a36Sopenharmony_ci return 1; 181662306a36Sopenharmony_ci return 0; 181762306a36Sopenharmony_ci} 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_cistatic void nfs_ooo_merge(struct nfs_inode *nfsi, 182062306a36Sopenharmony_ci u64 start, u64 end) 182162306a36Sopenharmony_ci{ 182262306a36Sopenharmony_ci int i, cnt; 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci if (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER) 182562306a36Sopenharmony_ci /* No point merging anything */ 182662306a36Sopenharmony_ci return; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci if (!nfsi->ooo) { 182962306a36Sopenharmony_ci nfsi->ooo = kmalloc(sizeof(*nfsi->ooo), GFP_ATOMIC); 183062306a36Sopenharmony_ci if (!nfsi->ooo) { 183162306a36Sopenharmony_ci nfsi->cache_validity |= NFS_INO_DATA_INVAL_DEFER; 183262306a36Sopenharmony_ci return; 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci nfsi->ooo->cnt = 0; 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci /* add this range, merging if possible */ 183862306a36Sopenharmony_ci cnt = nfsi->ooo->cnt; 183962306a36Sopenharmony_ci for (i = 0; i < cnt; i++) { 184062306a36Sopenharmony_ci if (end == nfsi->ooo->gap[i].start) 184162306a36Sopenharmony_ci end = nfsi->ooo->gap[i].end; 184262306a36Sopenharmony_ci else if (start == nfsi->ooo->gap[i].end) 184362306a36Sopenharmony_ci start = nfsi->ooo->gap[i].start; 184462306a36Sopenharmony_ci else 184562306a36Sopenharmony_ci continue; 184662306a36Sopenharmony_ci /* Remove 'i' from table and loop to insert the new range */ 184762306a36Sopenharmony_ci cnt -= 1; 184862306a36Sopenharmony_ci nfsi->ooo->gap[i] = nfsi->ooo->gap[cnt]; 184962306a36Sopenharmony_ci i = -1; 185062306a36Sopenharmony_ci } 185162306a36Sopenharmony_ci if (start != end) { 185262306a36Sopenharmony_ci if (cnt >= ARRAY_SIZE(nfsi->ooo->gap)) { 185362306a36Sopenharmony_ci nfsi->cache_validity |= NFS_INO_DATA_INVAL_DEFER; 185462306a36Sopenharmony_ci kfree(nfsi->ooo); 185562306a36Sopenharmony_ci nfsi->ooo = NULL; 185662306a36Sopenharmony_ci return; 185762306a36Sopenharmony_ci } 185862306a36Sopenharmony_ci nfsi->ooo->gap[cnt].start = start; 185962306a36Sopenharmony_ci nfsi->ooo->gap[cnt].end = end; 186062306a36Sopenharmony_ci cnt += 1; 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci nfsi->ooo->cnt = cnt; 186362306a36Sopenharmony_ci} 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_cistatic void nfs_ooo_record(struct nfs_inode *nfsi, 186662306a36Sopenharmony_ci struct nfs_fattr *fattr) 186762306a36Sopenharmony_ci{ 186862306a36Sopenharmony_ci /* This reply was out-of-order, so record in the 186962306a36Sopenharmony_ci * pre/post change id, possibly cancelling 187062306a36Sopenharmony_ci * gaps created when iversion was jumpped forward. 187162306a36Sopenharmony_ci */ 187262306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) && 187362306a36Sopenharmony_ci (fattr->valid & NFS_ATTR_FATTR_PRECHANGE)) 187462306a36Sopenharmony_ci nfs_ooo_merge(nfsi, 187562306a36Sopenharmony_ci fattr->change_attr, 187662306a36Sopenharmony_ci fattr->pre_change_attr); 187762306a36Sopenharmony_ci} 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_cistatic int nfs_refresh_inode_locked(struct inode *inode, 188062306a36Sopenharmony_ci struct nfs_fattr *fattr) 188162306a36Sopenharmony_ci{ 188262306a36Sopenharmony_ci int attr_cmp = nfs_inode_attrs_cmp(fattr, inode); 188362306a36Sopenharmony_ci int ret = 0; 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci trace_nfs_refresh_inode_enter(inode); 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci if (attr_cmp > 0 || nfs_inode_finish_partial_attr_update(fattr, inode)) 188862306a36Sopenharmony_ci ret = nfs_update_inode(inode, fattr); 188962306a36Sopenharmony_ci else { 189062306a36Sopenharmony_ci nfs_ooo_record(NFS_I(inode), fattr); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (attr_cmp == 0) 189362306a36Sopenharmony_ci ret = nfs_check_inode_attributes(inode, fattr); 189462306a36Sopenharmony_ci } 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci trace_nfs_refresh_inode_exit(inode, ret); 189762306a36Sopenharmony_ci return ret; 189862306a36Sopenharmony_ci} 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci/** 190162306a36Sopenharmony_ci * nfs_refresh_inode - try to update the inode attribute cache 190262306a36Sopenharmony_ci * @inode: pointer to inode 190362306a36Sopenharmony_ci * @fattr: updated attributes 190462306a36Sopenharmony_ci * 190562306a36Sopenharmony_ci * Check that an RPC call that returned attributes has not overlapped with 190662306a36Sopenharmony_ci * other recent updates of the inode metadata, then decide whether it is 190762306a36Sopenharmony_ci * safe to do a full update of the inode attributes, or whether just to 190862306a36Sopenharmony_ci * call nfs_check_inode_attributes. 190962306a36Sopenharmony_ci */ 191062306a36Sopenharmony_ciint nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) 191162306a36Sopenharmony_ci{ 191262306a36Sopenharmony_ci int status; 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR) == 0) 191562306a36Sopenharmony_ci return 0; 191662306a36Sopenharmony_ci spin_lock(&inode->i_lock); 191762306a36Sopenharmony_ci status = nfs_refresh_inode_locked(inode, fattr); 191862306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci return status; 192162306a36Sopenharmony_ci} 192262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_refresh_inode); 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_cistatic int nfs_post_op_update_inode_locked(struct inode *inode, 192562306a36Sopenharmony_ci struct nfs_fattr *fattr, unsigned int invalid) 192662306a36Sopenharmony_ci{ 192762306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 192862306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_DATA; 192962306a36Sopenharmony_ci nfs_set_cache_invalid(inode, invalid); 193062306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR) == 0) 193162306a36Sopenharmony_ci return 0; 193262306a36Sopenharmony_ci return nfs_refresh_inode_locked(inode, fattr); 193362306a36Sopenharmony_ci} 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci/** 193662306a36Sopenharmony_ci * nfs_post_op_update_inode - try to update the inode attribute cache 193762306a36Sopenharmony_ci * @inode: pointer to inode 193862306a36Sopenharmony_ci * @fattr: updated attributes 193962306a36Sopenharmony_ci * 194062306a36Sopenharmony_ci * After an operation that has changed the inode metadata, mark the 194162306a36Sopenharmony_ci * attribute cache as being invalid, then try to update it. 194262306a36Sopenharmony_ci * 194362306a36Sopenharmony_ci * NB: if the server didn't return any post op attributes, this 194462306a36Sopenharmony_ci * function will force the retrieval of attributes before the next 194562306a36Sopenharmony_ci * NFS request. Thus it should be used only for operations that 194662306a36Sopenharmony_ci * are expected to change one or more attributes, to avoid 194762306a36Sopenharmony_ci * unnecessary NFS requests and trips through nfs_update_inode(). 194862306a36Sopenharmony_ci */ 194962306a36Sopenharmony_ciint nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) 195062306a36Sopenharmony_ci{ 195162306a36Sopenharmony_ci int status; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci spin_lock(&inode->i_lock); 195462306a36Sopenharmony_ci nfs_fattr_set_barrier(fattr); 195562306a36Sopenharmony_ci status = nfs_post_op_update_inode_locked(inode, fattr, 195662306a36Sopenharmony_ci NFS_INO_INVALID_CHANGE 195762306a36Sopenharmony_ci | NFS_INO_INVALID_CTIME 195862306a36Sopenharmony_ci | NFS_INO_REVAL_FORCED); 195962306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci return status; 196262306a36Sopenharmony_ci} 196362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_post_op_update_inode); 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci/** 196662306a36Sopenharmony_ci * nfs_post_op_update_inode_force_wcc_locked - update the inode attribute cache 196762306a36Sopenharmony_ci * @inode: pointer to inode 196862306a36Sopenharmony_ci * @fattr: updated attributes 196962306a36Sopenharmony_ci * 197062306a36Sopenharmony_ci * After an operation that has changed the inode metadata, mark the 197162306a36Sopenharmony_ci * attribute cache as being invalid, then try to update it. Fake up 197262306a36Sopenharmony_ci * weak cache consistency data, if none exist. 197362306a36Sopenharmony_ci * 197462306a36Sopenharmony_ci * This function is mainly designed to be used by the ->write_done() functions. 197562306a36Sopenharmony_ci */ 197662306a36Sopenharmony_ciint nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr) 197762306a36Sopenharmony_ci{ 197862306a36Sopenharmony_ci int attr_cmp = nfs_inode_attrs_cmp(fattr, inode); 197962306a36Sopenharmony_ci int status; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci /* Don't do a WCC update if these attributes are already stale */ 198262306a36Sopenharmony_ci if (attr_cmp < 0) 198362306a36Sopenharmony_ci return 0; 198462306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR) == 0 || !attr_cmp) { 198562306a36Sopenharmony_ci /* Record the pre/post change info before clearing PRECHANGE */ 198662306a36Sopenharmony_ci nfs_ooo_record(NFS_I(inode), fattr); 198762306a36Sopenharmony_ci fattr->valid &= ~(NFS_ATTR_FATTR_PRECHANGE 198862306a36Sopenharmony_ci | NFS_ATTR_FATTR_PRESIZE 198962306a36Sopenharmony_ci | NFS_ATTR_FATTR_PREMTIME 199062306a36Sopenharmony_ci | NFS_ATTR_FATTR_PRECTIME); 199162306a36Sopenharmony_ci goto out_noforce; 199262306a36Sopenharmony_ci } 199362306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && 199462306a36Sopenharmony_ci (fattr->valid & NFS_ATTR_FATTR_PRECHANGE) == 0) { 199562306a36Sopenharmony_ci fattr->pre_change_attr = inode_peek_iversion_raw(inode); 199662306a36Sopenharmony_ci fattr->valid |= NFS_ATTR_FATTR_PRECHANGE; 199762306a36Sopenharmony_ci } 199862306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_CTIME) != 0 && 199962306a36Sopenharmony_ci (fattr->valid & NFS_ATTR_FATTR_PRECTIME) == 0) { 200062306a36Sopenharmony_ci fattr->pre_ctime = inode_get_ctime(inode); 200162306a36Sopenharmony_ci fattr->valid |= NFS_ATTR_FATTR_PRECTIME; 200262306a36Sopenharmony_ci } 200362306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_MTIME) != 0 && 200462306a36Sopenharmony_ci (fattr->valid & NFS_ATTR_FATTR_PREMTIME) == 0) { 200562306a36Sopenharmony_ci fattr->pre_mtime = inode->i_mtime; 200662306a36Sopenharmony_ci fattr->valid |= NFS_ATTR_FATTR_PREMTIME; 200762306a36Sopenharmony_ci } 200862306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_SIZE) != 0 && 200962306a36Sopenharmony_ci (fattr->valid & NFS_ATTR_FATTR_PRESIZE) == 0) { 201062306a36Sopenharmony_ci fattr->pre_size = i_size_read(inode); 201162306a36Sopenharmony_ci fattr->valid |= NFS_ATTR_FATTR_PRESIZE; 201262306a36Sopenharmony_ci } 201362306a36Sopenharmony_ciout_noforce: 201462306a36Sopenharmony_ci status = nfs_post_op_update_inode_locked(inode, fattr, 201562306a36Sopenharmony_ci NFS_INO_INVALID_CHANGE 201662306a36Sopenharmony_ci | NFS_INO_INVALID_CTIME 201762306a36Sopenharmony_ci | NFS_INO_INVALID_MTIME 201862306a36Sopenharmony_ci | NFS_INO_INVALID_BLOCKS); 201962306a36Sopenharmony_ci return status; 202062306a36Sopenharmony_ci} 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci/** 202362306a36Sopenharmony_ci * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache 202462306a36Sopenharmony_ci * @inode: pointer to inode 202562306a36Sopenharmony_ci * @fattr: updated attributes 202662306a36Sopenharmony_ci * 202762306a36Sopenharmony_ci * After an operation that has changed the inode metadata, mark the 202862306a36Sopenharmony_ci * attribute cache as being invalid, then try to update it. Fake up 202962306a36Sopenharmony_ci * weak cache consistency data, if none exist. 203062306a36Sopenharmony_ci * 203162306a36Sopenharmony_ci * This function is mainly designed to be used by the ->write_done() functions. 203262306a36Sopenharmony_ci */ 203362306a36Sopenharmony_ciint nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr) 203462306a36Sopenharmony_ci{ 203562306a36Sopenharmony_ci int status; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci spin_lock(&inode->i_lock); 203862306a36Sopenharmony_ci nfs_fattr_set_barrier(fattr); 203962306a36Sopenharmony_ci status = nfs_post_op_update_inode_force_wcc_locked(inode, fattr); 204062306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 204162306a36Sopenharmony_ci return status; 204262306a36Sopenharmony_ci} 204362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_post_op_update_inode_force_wcc); 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci/* 204762306a36Sopenharmony_ci * Many nfs protocol calls return the new file attributes after 204862306a36Sopenharmony_ci * an operation. Here we update the inode to reflect the state 204962306a36Sopenharmony_ci * of the server's inode. 205062306a36Sopenharmony_ci * 205162306a36Sopenharmony_ci * This is a bit tricky because we have to make sure all dirty pages 205262306a36Sopenharmony_ci * have been sent off to the server before calling invalidate_inode_pages. 205362306a36Sopenharmony_ci * To make sure no other process adds more write requests while we try 205462306a36Sopenharmony_ci * our best to flush them, we make them sleep during the attribute refresh. 205562306a36Sopenharmony_ci * 205662306a36Sopenharmony_ci * A very similar scenario holds for the dir cache. 205762306a36Sopenharmony_ci */ 205862306a36Sopenharmony_cistatic int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) 205962306a36Sopenharmony_ci{ 206062306a36Sopenharmony_ci struct nfs_server *server = NFS_SERVER(inode); 206162306a36Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 206262306a36Sopenharmony_ci loff_t cur_isize, new_isize; 206362306a36Sopenharmony_ci u64 fattr_supported = server->fattr_valid; 206462306a36Sopenharmony_ci unsigned long invalid = 0; 206562306a36Sopenharmony_ci unsigned long now = jiffies; 206662306a36Sopenharmony_ci unsigned long save_cache_validity; 206762306a36Sopenharmony_ci bool have_writers = nfs_file_has_buffered_writers(nfsi); 206862306a36Sopenharmony_ci bool cache_revalidated = true; 206962306a36Sopenharmony_ci bool attr_changed = false; 207062306a36Sopenharmony_ci bool have_delegation; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n", 207362306a36Sopenharmony_ci __func__, inode->i_sb->s_id, inode->i_ino, 207462306a36Sopenharmony_ci nfs_display_fhandle_hash(NFS_FH(inode)), 207562306a36Sopenharmony_ci atomic_read(&inode->i_count), fattr->valid); 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci if (!(fattr->valid & NFS_ATTR_FATTR_FILEID)) { 207862306a36Sopenharmony_ci /* Only a mounted-on-fileid? Just exit */ 207962306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) 208062306a36Sopenharmony_ci return 0; 208162306a36Sopenharmony_ci /* Has the inode gone and changed behind our back? */ 208262306a36Sopenharmony_ci } else if (nfsi->fileid != fattr->fileid) { 208362306a36Sopenharmony_ci /* Is this perhaps the mounted-on fileid? */ 208462306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) && 208562306a36Sopenharmony_ci nfsi->fileid == fattr->mounted_on_fileid) 208662306a36Sopenharmony_ci return 0; 208762306a36Sopenharmony_ci printk(KERN_ERR "NFS: server %s error: fileid changed\n" 208862306a36Sopenharmony_ci "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n", 208962306a36Sopenharmony_ci NFS_SERVER(inode)->nfs_client->cl_hostname, 209062306a36Sopenharmony_ci inode->i_sb->s_id, (long long)nfsi->fileid, 209162306a36Sopenharmony_ci (long long)fattr->fileid); 209262306a36Sopenharmony_ci goto out_err; 209362306a36Sopenharmony_ci } 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci /* 209662306a36Sopenharmony_ci * Make sure the inode's type hasn't changed. 209762306a36Sopenharmony_ci */ 209862306a36Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && inode_wrong_type(inode, fattr->mode)) { 209962306a36Sopenharmony_ci /* 210062306a36Sopenharmony_ci * Big trouble! The inode has become a different object. 210162306a36Sopenharmony_ci */ 210262306a36Sopenharmony_ci printk(KERN_DEBUG "NFS: %s: inode %lu mode changed, %07o to %07o\n", 210362306a36Sopenharmony_ci __func__, inode->i_ino, inode->i_mode, fattr->mode); 210462306a36Sopenharmony_ci goto out_err; 210562306a36Sopenharmony_ci } 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci /* Update the fsid? */ 210862306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) && 210962306a36Sopenharmony_ci !nfs_fsid_equal(&server->fsid, &fattr->fsid) && 211062306a36Sopenharmony_ci !IS_AUTOMOUNT(inode)) 211162306a36Sopenharmony_ci server->fsid = fattr->fsid; 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci /* Save the delegation state before clearing cache_validity */ 211462306a36Sopenharmony_ci have_delegation = nfs_have_delegated_attributes(inode); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci /* 211762306a36Sopenharmony_ci * Update the read time so we don't revalidate too often. 211862306a36Sopenharmony_ci */ 211962306a36Sopenharmony_ci nfsi->read_cache_jiffies = fattr->time_start; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci save_cache_validity = nfsi->cache_validity; 212262306a36Sopenharmony_ci nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR 212362306a36Sopenharmony_ci | NFS_INO_INVALID_ATIME 212462306a36Sopenharmony_ci | NFS_INO_REVAL_FORCED 212562306a36Sopenharmony_ci | NFS_INO_INVALID_BLOCKS); 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci /* Do atomic weak cache consistency updates */ 212862306a36Sopenharmony_ci nfs_wcc_update_inode(inode, fattr); 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci if (pnfs_layoutcommit_outstanding(inode)) { 213162306a36Sopenharmony_ci nfsi->cache_validity |= 213262306a36Sopenharmony_ci save_cache_validity & 213362306a36Sopenharmony_ci (NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME | 213462306a36Sopenharmony_ci NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE | 213562306a36Sopenharmony_ci NFS_INO_INVALID_BLOCKS); 213662306a36Sopenharmony_ci cache_revalidated = false; 213762306a36Sopenharmony_ci } 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci /* More cache consistency checks */ 214062306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CHANGE) { 214162306a36Sopenharmony_ci if (!have_writers && nfsi->ooo && nfsi->ooo->cnt == 1 && 214262306a36Sopenharmony_ci nfsi->ooo->gap[0].end == inode_peek_iversion_raw(inode)) { 214362306a36Sopenharmony_ci /* There is one remaining gap that hasn't been 214462306a36Sopenharmony_ci * merged into iversion - do that now. 214562306a36Sopenharmony_ci */ 214662306a36Sopenharmony_ci inode_set_iversion_raw(inode, nfsi->ooo->gap[0].start); 214762306a36Sopenharmony_ci kfree(nfsi->ooo); 214862306a36Sopenharmony_ci nfsi->ooo = NULL; 214962306a36Sopenharmony_ci } 215062306a36Sopenharmony_ci if (!inode_eq_iversion_raw(inode, fattr->change_attr)) { 215162306a36Sopenharmony_ci /* Could it be a race with writeback? */ 215262306a36Sopenharmony_ci if (!(have_writers || have_delegation)) { 215362306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_DATA 215462306a36Sopenharmony_ci | NFS_INO_INVALID_ACCESS 215562306a36Sopenharmony_ci | NFS_INO_INVALID_ACL 215662306a36Sopenharmony_ci | NFS_INO_INVALID_XATTR; 215762306a36Sopenharmony_ci /* Force revalidate of all attributes */ 215862306a36Sopenharmony_ci save_cache_validity |= NFS_INO_INVALID_CTIME 215962306a36Sopenharmony_ci | NFS_INO_INVALID_MTIME 216062306a36Sopenharmony_ci | NFS_INO_INVALID_SIZE 216162306a36Sopenharmony_ci | NFS_INO_INVALID_BLOCKS 216262306a36Sopenharmony_ci | NFS_INO_INVALID_NLINK 216362306a36Sopenharmony_ci | NFS_INO_INVALID_MODE 216462306a36Sopenharmony_ci | NFS_INO_INVALID_OTHER; 216562306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 216662306a36Sopenharmony_ci nfs_force_lookup_revalidate(inode); 216762306a36Sopenharmony_ci attr_changed = true; 216862306a36Sopenharmony_ci dprintk("NFS: change_attr change on server for file %s/%ld\n", 216962306a36Sopenharmony_ci inode->i_sb->s_id, 217062306a36Sopenharmony_ci inode->i_ino); 217162306a36Sopenharmony_ci } else if (!have_delegation) { 217262306a36Sopenharmony_ci nfs_ooo_record(nfsi, fattr); 217362306a36Sopenharmony_ci nfs_ooo_merge(nfsi, inode_peek_iversion_raw(inode), 217462306a36Sopenharmony_ci fattr->change_attr); 217562306a36Sopenharmony_ci } 217662306a36Sopenharmony_ci inode_set_iversion_raw(inode, fattr->change_attr); 217762306a36Sopenharmony_ci } 217862306a36Sopenharmony_ci } else { 217962306a36Sopenharmony_ci nfsi->cache_validity |= 218062306a36Sopenharmony_ci save_cache_validity & NFS_INO_INVALID_CHANGE; 218162306a36Sopenharmony_ci if (!have_delegation || 218262306a36Sopenharmony_ci (nfsi->cache_validity & NFS_INO_INVALID_CHANGE) != 0) 218362306a36Sopenharmony_ci cache_revalidated = false; 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MTIME) 218762306a36Sopenharmony_ci inode->i_mtime = fattr->mtime; 218862306a36Sopenharmony_ci else if (fattr_supported & NFS_ATTR_FATTR_MTIME) 218962306a36Sopenharmony_ci nfsi->cache_validity |= 219062306a36Sopenharmony_ci save_cache_validity & NFS_INO_INVALID_MTIME; 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CTIME) 219362306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, fattr->ctime); 219462306a36Sopenharmony_ci else if (fattr_supported & NFS_ATTR_FATTR_CTIME) 219562306a36Sopenharmony_ci nfsi->cache_validity |= 219662306a36Sopenharmony_ci save_cache_validity & NFS_INO_INVALID_CTIME; 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci /* Check if our cached file size is stale */ 219962306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_SIZE) { 220062306a36Sopenharmony_ci new_isize = nfs_size_to_loff_t(fattr->size); 220162306a36Sopenharmony_ci cur_isize = i_size_read(inode); 220262306a36Sopenharmony_ci if (new_isize != cur_isize && !have_delegation) { 220362306a36Sopenharmony_ci /* Do we perhaps have any outstanding writes, or has 220462306a36Sopenharmony_ci * the file grown beyond our last write? */ 220562306a36Sopenharmony_ci if (!nfs_have_writebacks(inode) || new_isize > cur_isize) { 220662306a36Sopenharmony_ci trace_nfs_size_update(inode, new_isize); 220762306a36Sopenharmony_ci i_size_write(inode, new_isize); 220862306a36Sopenharmony_ci if (!have_writers) 220962306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_DATA; 221062306a36Sopenharmony_ci } 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci if (new_isize == 0 && 221362306a36Sopenharmony_ci !(fattr->valid & (NFS_ATTR_FATTR_SPACE_USED | 221462306a36Sopenharmony_ci NFS_ATTR_FATTR_BLOCKS_USED))) { 221562306a36Sopenharmony_ci fattr->du.nfs3.used = 0; 221662306a36Sopenharmony_ci fattr->valid |= NFS_ATTR_FATTR_SPACE_USED; 221762306a36Sopenharmony_ci } 221862306a36Sopenharmony_ci } else 221962306a36Sopenharmony_ci nfsi->cache_validity |= 222062306a36Sopenharmony_ci save_cache_validity & NFS_INO_INVALID_SIZE; 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_ATIME) 222362306a36Sopenharmony_ci inode->i_atime = fattr->atime; 222462306a36Sopenharmony_ci else if (fattr_supported & NFS_ATTR_FATTR_ATIME) 222562306a36Sopenharmony_ci nfsi->cache_validity |= 222662306a36Sopenharmony_ci save_cache_validity & NFS_INO_INVALID_ATIME; 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MODE) { 222962306a36Sopenharmony_ci if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { 223062306a36Sopenharmony_ci umode_t newmode = inode->i_mode & S_IFMT; 223162306a36Sopenharmony_ci newmode |= fattr->mode & S_IALLUGO; 223262306a36Sopenharmony_ci inode->i_mode = newmode; 223362306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_ACCESS 223462306a36Sopenharmony_ci | NFS_INO_INVALID_ACL; 223562306a36Sopenharmony_ci } 223662306a36Sopenharmony_ci } else if (fattr_supported & NFS_ATTR_FATTR_MODE) 223762306a36Sopenharmony_ci nfsi->cache_validity |= 223862306a36Sopenharmony_ci save_cache_validity & NFS_INO_INVALID_MODE; 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_OWNER) { 224162306a36Sopenharmony_ci if (!uid_eq(inode->i_uid, fattr->uid)) { 224262306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_ACCESS 224362306a36Sopenharmony_ci | NFS_INO_INVALID_ACL; 224462306a36Sopenharmony_ci inode->i_uid = fattr->uid; 224562306a36Sopenharmony_ci } 224662306a36Sopenharmony_ci } else if (fattr_supported & NFS_ATTR_FATTR_OWNER) 224762306a36Sopenharmony_ci nfsi->cache_validity |= 224862306a36Sopenharmony_ci save_cache_validity & NFS_INO_INVALID_OTHER; 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_GROUP) { 225162306a36Sopenharmony_ci if (!gid_eq(inode->i_gid, fattr->gid)) { 225262306a36Sopenharmony_ci invalid |= NFS_INO_INVALID_ACCESS 225362306a36Sopenharmony_ci | NFS_INO_INVALID_ACL; 225462306a36Sopenharmony_ci inode->i_gid = fattr->gid; 225562306a36Sopenharmony_ci } 225662306a36Sopenharmony_ci } else if (fattr_supported & NFS_ATTR_FATTR_GROUP) 225762306a36Sopenharmony_ci nfsi->cache_validity |= 225862306a36Sopenharmony_ci save_cache_validity & NFS_INO_INVALID_OTHER; 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_NLINK) { 226162306a36Sopenharmony_ci if (inode->i_nlink != fattr->nlink) 226262306a36Sopenharmony_ci set_nlink(inode, fattr->nlink); 226362306a36Sopenharmony_ci } else if (fattr_supported & NFS_ATTR_FATTR_NLINK) 226462306a36Sopenharmony_ci nfsi->cache_validity |= 226562306a36Sopenharmony_ci save_cache_validity & NFS_INO_INVALID_NLINK; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { 226862306a36Sopenharmony_ci /* 226962306a36Sopenharmony_ci * report the blocks in 512byte units 227062306a36Sopenharmony_ci */ 227162306a36Sopenharmony_ci inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); 227262306a36Sopenharmony_ci } else if (fattr_supported & NFS_ATTR_FATTR_SPACE_USED) 227362306a36Sopenharmony_ci nfsi->cache_validity |= 227462306a36Sopenharmony_ci save_cache_validity & NFS_INO_INVALID_BLOCKS; 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) 227762306a36Sopenharmony_ci inode->i_blocks = fattr->du.nfs2.blocks; 227862306a36Sopenharmony_ci else if (fattr_supported & NFS_ATTR_FATTR_BLOCKS_USED) 227962306a36Sopenharmony_ci nfsi->cache_validity |= 228062306a36Sopenharmony_ci save_cache_validity & NFS_INO_INVALID_BLOCKS; 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci /* Update attrtimeo value if we're out of the unstable period */ 228362306a36Sopenharmony_ci if (attr_changed) { 228462306a36Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); 228562306a36Sopenharmony_ci nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); 228662306a36Sopenharmony_ci nfsi->attrtimeo_timestamp = now; 228762306a36Sopenharmony_ci /* Set barrier to be more recent than all outstanding updates */ 228862306a36Sopenharmony_ci nfsi->attr_gencount = nfs_inc_attr_generation_counter(); 228962306a36Sopenharmony_ci } else { 229062306a36Sopenharmony_ci if (cache_revalidated) { 229162306a36Sopenharmony_ci if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, 229262306a36Sopenharmony_ci nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) { 229362306a36Sopenharmony_ci nfsi->attrtimeo <<= 1; 229462306a36Sopenharmony_ci if (nfsi->attrtimeo > NFS_MAXATTRTIMEO(inode)) 229562306a36Sopenharmony_ci nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); 229662306a36Sopenharmony_ci } 229762306a36Sopenharmony_ci nfsi->attrtimeo_timestamp = now; 229862306a36Sopenharmony_ci } 229962306a36Sopenharmony_ci /* Set the barrier to be more recent than this fattr */ 230062306a36Sopenharmony_ci if ((long)(fattr->gencount - nfsi->attr_gencount) > 0) 230162306a36Sopenharmony_ci nfsi->attr_gencount = fattr->gencount; 230262306a36Sopenharmony_ci } 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci /* Don't invalidate the data if we were to blame */ 230562306a36Sopenharmony_ci if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) 230662306a36Sopenharmony_ci || S_ISLNK(inode->i_mode))) 230762306a36Sopenharmony_ci invalid &= ~NFS_INO_INVALID_DATA; 230862306a36Sopenharmony_ci nfs_set_cache_invalid(inode, invalid); 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci return 0; 231162306a36Sopenharmony_ci out_err: 231262306a36Sopenharmony_ci /* 231362306a36Sopenharmony_ci * No need to worry about unhashing the dentry, as the 231462306a36Sopenharmony_ci * lookup validation will know that the inode is bad. 231562306a36Sopenharmony_ci * (But we fall through to invalidate the caches.) 231662306a36Sopenharmony_ci */ 231762306a36Sopenharmony_ci nfs_set_inode_stale_locked(inode); 231862306a36Sopenharmony_ci return -ESTALE; 231962306a36Sopenharmony_ci} 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_cistruct inode *nfs_alloc_inode(struct super_block *sb) 232262306a36Sopenharmony_ci{ 232362306a36Sopenharmony_ci struct nfs_inode *nfsi; 232462306a36Sopenharmony_ci nfsi = alloc_inode_sb(sb, nfs_inode_cachep, GFP_KERNEL); 232562306a36Sopenharmony_ci if (!nfsi) 232662306a36Sopenharmony_ci return NULL; 232762306a36Sopenharmony_ci nfsi->flags = 0UL; 232862306a36Sopenharmony_ci nfsi->cache_validity = 0UL; 232962306a36Sopenharmony_ci nfsi->ooo = NULL; 233062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NFS_V4) 233162306a36Sopenharmony_ci nfsi->nfs4_acl = NULL; 233262306a36Sopenharmony_ci#endif /* CONFIG_NFS_V4 */ 233362306a36Sopenharmony_ci#ifdef CONFIG_NFS_V4_2 233462306a36Sopenharmony_ci nfsi->xattr_cache = NULL; 233562306a36Sopenharmony_ci#endif 233662306a36Sopenharmony_ci nfs_netfs_inode_init(nfsi); 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_ci return &nfsi->vfs_inode; 233962306a36Sopenharmony_ci} 234062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_alloc_inode); 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_civoid nfs_free_inode(struct inode *inode) 234362306a36Sopenharmony_ci{ 234462306a36Sopenharmony_ci kfree(NFS_I(inode)->ooo); 234562306a36Sopenharmony_ci kmem_cache_free(nfs_inode_cachep, NFS_I(inode)); 234662306a36Sopenharmony_ci} 234762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_free_inode); 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_cistatic inline void nfs4_init_once(struct nfs_inode *nfsi) 235062306a36Sopenharmony_ci{ 235162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NFS_V4) 235262306a36Sopenharmony_ci INIT_LIST_HEAD(&nfsi->open_states); 235362306a36Sopenharmony_ci nfsi->delegation = NULL; 235462306a36Sopenharmony_ci init_rwsem(&nfsi->rwsem); 235562306a36Sopenharmony_ci nfsi->layout = NULL; 235662306a36Sopenharmony_ci#endif 235762306a36Sopenharmony_ci} 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_cistatic void init_once(void *foo) 236062306a36Sopenharmony_ci{ 236162306a36Sopenharmony_ci struct nfs_inode *nfsi = foo; 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci inode_init_once(&nfsi->vfs_inode); 236462306a36Sopenharmony_ci INIT_LIST_HEAD(&nfsi->open_files); 236562306a36Sopenharmony_ci INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); 236662306a36Sopenharmony_ci INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); 236762306a36Sopenharmony_ci nfs4_init_once(nfsi); 236862306a36Sopenharmony_ci} 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_cistatic int __init nfs_init_inodecache(void) 237162306a36Sopenharmony_ci{ 237262306a36Sopenharmony_ci nfs_inode_cachep = kmem_cache_create("nfs_inode_cache", 237362306a36Sopenharmony_ci sizeof(struct nfs_inode), 237462306a36Sopenharmony_ci 0, (SLAB_RECLAIM_ACCOUNT| 237562306a36Sopenharmony_ci SLAB_MEM_SPREAD|SLAB_ACCOUNT), 237662306a36Sopenharmony_ci init_once); 237762306a36Sopenharmony_ci if (nfs_inode_cachep == NULL) 237862306a36Sopenharmony_ci return -ENOMEM; 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_ci return 0; 238162306a36Sopenharmony_ci} 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_cistatic void nfs_destroy_inodecache(void) 238462306a36Sopenharmony_ci{ 238562306a36Sopenharmony_ci /* 238662306a36Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 238762306a36Sopenharmony_ci * destroy cache. 238862306a36Sopenharmony_ci */ 238962306a36Sopenharmony_ci rcu_barrier(); 239062306a36Sopenharmony_ci kmem_cache_destroy(nfs_inode_cachep); 239162306a36Sopenharmony_ci} 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_cistruct workqueue_struct *nfsiod_workqueue; 239462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfsiod_workqueue); 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci/* 239762306a36Sopenharmony_ci * start up the nfsiod workqueue 239862306a36Sopenharmony_ci */ 239962306a36Sopenharmony_cistatic int nfsiod_start(void) 240062306a36Sopenharmony_ci{ 240162306a36Sopenharmony_ci struct workqueue_struct *wq; 240262306a36Sopenharmony_ci dprintk("RPC: creating workqueue nfsiod\n"); 240362306a36Sopenharmony_ci wq = alloc_workqueue("nfsiod", WQ_MEM_RECLAIM | WQ_UNBOUND, 0); 240462306a36Sopenharmony_ci if (wq == NULL) 240562306a36Sopenharmony_ci return -ENOMEM; 240662306a36Sopenharmony_ci nfsiod_workqueue = wq; 240762306a36Sopenharmony_ci return 0; 240862306a36Sopenharmony_ci} 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci/* 241162306a36Sopenharmony_ci * Destroy the nfsiod workqueue 241262306a36Sopenharmony_ci */ 241362306a36Sopenharmony_cistatic void nfsiod_stop(void) 241462306a36Sopenharmony_ci{ 241562306a36Sopenharmony_ci struct workqueue_struct *wq; 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci wq = nfsiod_workqueue; 241862306a36Sopenharmony_ci if (wq == NULL) 241962306a36Sopenharmony_ci return; 242062306a36Sopenharmony_ci nfsiod_workqueue = NULL; 242162306a36Sopenharmony_ci destroy_workqueue(wq); 242262306a36Sopenharmony_ci} 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ciunsigned int nfs_net_id; 242562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_net_id); 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_cistatic int nfs_net_init(struct net *net) 242862306a36Sopenharmony_ci{ 242962306a36Sopenharmony_ci nfs_clients_init(net); 243062306a36Sopenharmony_ci return nfs_fs_proc_net_init(net); 243162306a36Sopenharmony_ci} 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_cistatic void nfs_net_exit(struct net *net) 243462306a36Sopenharmony_ci{ 243562306a36Sopenharmony_ci nfs_fs_proc_net_exit(net); 243662306a36Sopenharmony_ci nfs_clients_exit(net); 243762306a36Sopenharmony_ci} 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_cistatic struct pernet_operations nfs_net_ops = { 244062306a36Sopenharmony_ci .init = nfs_net_init, 244162306a36Sopenharmony_ci .exit = nfs_net_exit, 244262306a36Sopenharmony_ci .id = &nfs_net_id, 244362306a36Sopenharmony_ci .size = sizeof(struct nfs_net), 244462306a36Sopenharmony_ci}; 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci/* 244762306a36Sopenharmony_ci * Initialize NFS 244862306a36Sopenharmony_ci */ 244962306a36Sopenharmony_cistatic int __init init_nfs_fs(void) 245062306a36Sopenharmony_ci{ 245162306a36Sopenharmony_ci int err; 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci err = nfs_sysfs_init(); 245462306a36Sopenharmony_ci if (err < 0) 245562306a36Sopenharmony_ci goto out10; 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci err = register_pernet_subsys(&nfs_net_ops); 245862306a36Sopenharmony_ci if (err < 0) 245962306a36Sopenharmony_ci goto out9; 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci err = nfsiod_start(); 246262306a36Sopenharmony_ci if (err) 246362306a36Sopenharmony_ci goto out7; 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci err = nfs_fs_proc_init(); 246662306a36Sopenharmony_ci if (err) 246762306a36Sopenharmony_ci goto out6; 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci err = nfs_init_nfspagecache(); 247062306a36Sopenharmony_ci if (err) 247162306a36Sopenharmony_ci goto out5; 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci err = nfs_init_inodecache(); 247462306a36Sopenharmony_ci if (err) 247562306a36Sopenharmony_ci goto out4; 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci err = nfs_init_readpagecache(); 247862306a36Sopenharmony_ci if (err) 247962306a36Sopenharmony_ci goto out3; 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci err = nfs_init_writepagecache(); 248262306a36Sopenharmony_ci if (err) 248362306a36Sopenharmony_ci goto out2; 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci err = nfs_init_directcache(); 248662306a36Sopenharmony_ci if (err) 248762306a36Sopenharmony_ci goto out1; 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci rpc_proc_register(&init_net, &nfs_rpcstat); 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci err = register_nfs_fs(); 249262306a36Sopenharmony_ci if (err) 249362306a36Sopenharmony_ci goto out0; 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci return 0; 249662306a36Sopenharmony_ciout0: 249762306a36Sopenharmony_ci rpc_proc_unregister(&init_net, "nfs"); 249862306a36Sopenharmony_ci nfs_destroy_directcache(); 249962306a36Sopenharmony_ciout1: 250062306a36Sopenharmony_ci nfs_destroy_writepagecache(); 250162306a36Sopenharmony_ciout2: 250262306a36Sopenharmony_ci nfs_destroy_readpagecache(); 250362306a36Sopenharmony_ciout3: 250462306a36Sopenharmony_ci nfs_destroy_inodecache(); 250562306a36Sopenharmony_ciout4: 250662306a36Sopenharmony_ci nfs_destroy_nfspagecache(); 250762306a36Sopenharmony_ciout5: 250862306a36Sopenharmony_ci nfs_fs_proc_exit(); 250962306a36Sopenharmony_ciout6: 251062306a36Sopenharmony_ci nfsiod_stop(); 251162306a36Sopenharmony_ciout7: 251262306a36Sopenharmony_ci unregister_pernet_subsys(&nfs_net_ops); 251362306a36Sopenharmony_ciout9: 251462306a36Sopenharmony_ci nfs_sysfs_exit(); 251562306a36Sopenharmony_ciout10: 251662306a36Sopenharmony_ci return err; 251762306a36Sopenharmony_ci} 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_cistatic void __exit exit_nfs_fs(void) 252062306a36Sopenharmony_ci{ 252162306a36Sopenharmony_ci nfs_destroy_directcache(); 252262306a36Sopenharmony_ci nfs_destroy_writepagecache(); 252362306a36Sopenharmony_ci nfs_destroy_readpagecache(); 252462306a36Sopenharmony_ci nfs_destroy_inodecache(); 252562306a36Sopenharmony_ci nfs_destroy_nfspagecache(); 252662306a36Sopenharmony_ci unregister_pernet_subsys(&nfs_net_ops); 252762306a36Sopenharmony_ci rpc_proc_unregister(&init_net, "nfs"); 252862306a36Sopenharmony_ci unregister_nfs_fs(); 252962306a36Sopenharmony_ci nfs_fs_proc_exit(); 253062306a36Sopenharmony_ci nfsiod_stop(); 253162306a36Sopenharmony_ci nfs_sysfs_exit(); 253262306a36Sopenharmony_ci} 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci/* Not quite true; I just maintain it */ 253562306a36Sopenharmony_ciMODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); 253662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 253762306a36Sopenharmony_cimodule_param(enable_ino64, bool, 0644); 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_cimodule_init(init_nfs_fs) 254062306a36Sopenharmony_cimodule_exit(exit_nfs_fs) 2541