18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/nfs/inode.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1992 Rick Sladkey 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * nfs inode and superblock handling functions 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Modularised by Alan Cox <alan@lxorguk.ukuu.org.uk>, while hacking some 108c2ecf20Sopenharmony_ci * experimental NFS changes. Modularisation taken straight from SYS5 fs. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Change to nfs_read_super() to permit NFS mounts to multi-homed hosts. 138c2ecf20Sopenharmony_ci * J.S.Peatfield@damtp.cam.ac.uk 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/init.h> 198c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 208c2ecf20Sopenharmony_ci#include <linux/time.h> 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/mm.h> 238c2ecf20Sopenharmony_ci#include <linux/string.h> 248c2ecf20Sopenharmony_ci#include <linux/stat.h> 258c2ecf20Sopenharmony_ci#include <linux/errno.h> 268c2ecf20Sopenharmony_ci#include <linux/unistd.h> 278c2ecf20Sopenharmony_ci#include <linux/sunrpc/clnt.h> 288c2ecf20Sopenharmony_ci#include <linux/sunrpc/stats.h> 298c2ecf20Sopenharmony_ci#include <linux/sunrpc/metrics.h> 308c2ecf20Sopenharmony_ci#include <linux/nfs_fs.h> 318c2ecf20Sopenharmony_ci#include <linux/nfs_mount.h> 328c2ecf20Sopenharmony_ci#include <linux/nfs4_mount.h> 338c2ecf20Sopenharmony_ci#include <linux/lockd/bind.h> 348c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 358c2ecf20Sopenharmony_ci#include <linux/mount.h> 368c2ecf20Sopenharmony_ci#include <linux/vfs.h> 378c2ecf20Sopenharmony_ci#include <linux/inet.h> 388c2ecf20Sopenharmony_ci#include <linux/nfs_xdr.h> 398c2ecf20Sopenharmony_ci#include <linux/slab.h> 408c2ecf20Sopenharmony_ci#include <linux/compat.h> 418c2ecf20Sopenharmony_ci#include <linux/freezer.h> 428c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 438c2ecf20Sopenharmony_ci#include <linux/iversion.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#include "nfs4_fs.h" 468c2ecf20Sopenharmony_ci#include "callback.h" 478c2ecf20Sopenharmony_ci#include "delegation.h" 488c2ecf20Sopenharmony_ci#include "iostat.h" 498c2ecf20Sopenharmony_ci#include "internal.h" 508c2ecf20Sopenharmony_ci#include "fscache.h" 518c2ecf20Sopenharmony_ci#include "pnfs.h" 528c2ecf20Sopenharmony_ci#include "nfs.h" 538c2ecf20Sopenharmony_ci#include "netns.h" 548c2ecf20Sopenharmony_ci#include "sysfs.h" 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#include "nfstrace.h" 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define NFSDBG_FACILITY NFSDBG_VFS 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define NFS_64_BIT_INODE_NUMBERS_ENABLED 1 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* Default is to see 64-bit inode numbers */ 638c2ecf20Sopenharmony_cistatic bool enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int nfs_update_inode(struct inode *, struct nfs_fattr *); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct kmem_cache * nfs_inode_cachep; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic inline unsigned long 708c2ecf20Sopenharmony_cinfs_fattr_to_ino_t(struct nfs_fattr *fattr) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci return nfs_fileid_to_ino_t(fattr->fileid); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int nfs_wait_killable(int mode) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci freezable_schedule_unsafe(); 788c2ecf20Sopenharmony_ci if (signal_pending_state(mode, current)) 798c2ecf20Sopenharmony_ci return -ERESTARTSYS; 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciint nfs_wait_bit_killable(struct wait_bit_key *key, int mode) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci return nfs_wait_killable(mode); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_wait_bit_killable); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/** 908c2ecf20Sopenharmony_ci * nfs_compat_user_ino64 - returns the user-visible inode number 918c2ecf20Sopenharmony_ci * @fileid: 64-bit fileid 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * This function returns a 32-bit inode number if the boot parameter 948c2ecf20Sopenharmony_ci * nfs.enable_ino64 is zero. 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ciu64 nfs_compat_user_ino64(u64 fileid) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 998c2ecf20Sopenharmony_ci compat_ulong_t ino; 1008c2ecf20Sopenharmony_ci#else 1018c2ecf20Sopenharmony_ci unsigned long ino; 1028c2ecf20Sopenharmony_ci#endif 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (enable_ino64) 1058c2ecf20Sopenharmony_ci return fileid; 1068c2ecf20Sopenharmony_ci ino = fileid; 1078c2ecf20Sopenharmony_ci if (sizeof(ino) < sizeof(fileid)) 1088c2ecf20Sopenharmony_ci ino ^= fileid >> (sizeof(fileid)-sizeof(ino)) * 8; 1098c2ecf20Sopenharmony_ci return ino; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ciint nfs_drop_inode(struct inode *inode) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci return NFS_STALE(inode) || generic_drop_inode(inode); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_drop_inode); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_civoid nfs_clear_inode(struct inode *inode) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci /* 1218c2ecf20Sopenharmony_ci * The following should never happen... 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci WARN_ON_ONCE(nfs_have_writebacks(inode)); 1248c2ecf20Sopenharmony_ci WARN_ON_ONCE(!list_empty(&NFS_I(inode)->open_files)); 1258c2ecf20Sopenharmony_ci nfs_zap_acl_cache(inode); 1268c2ecf20Sopenharmony_ci nfs_access_zap_cache(inode); 1278c2ecf20Sopenharmony_ci nfs_fscache_clear_inode(inode); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_clear_inode); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_civoid nfs_evict_inode(struct inode *inode) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci truncate_inode_pages_final(&inode->i_data); 1348c2ecf20Sopenharmony_ci clear_inode(inode); 1358c2ecf20Sopenharmony_ci nfs_clear_inode(inode); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ciint nfs_sync_inode(struct inode *inode) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci inode_dio_wait(inode); 1418c2ecf20Sopenharmony_ci return nfs_wb_all(inode); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_sync_inode); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/** 1468c2ecf20Sopenharmony_ci * nfs_sync_mapping - helper to flush all mmapped dirty data to disk 1478c2ecf20Sopenharmony_ci * @mapping: pointer to struct address_space 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_ciint nfs_sync_mapping(struct address_space *mapping) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci int ret = 0; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (mapping->nrpages != 0) { 1548c2ecf20Sopenharmony_ci unmap_mapping_range(mapping, 0, 0, 0); 1558c2ecf20Sopenharmony_ci ret = nfs_wb_all(mapping->host); 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci return ret; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic int nfs_attribute_timeout(struct inode *inode) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic bool nfs_check_cache_invalid_delegated(struct inode *inode, unsigned long flags) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Special case for the pagecache or access cache */ 1728c2ecf20Sopenharmony_ci if (flags == NFS_INO_REVAL_PAGECACHE && 1738c2ecf20Sopenharmony_ci !(cache_validity & NFS_INO_REVAL_FORCED)) 1748c2ecf20Sopenharmony_ci return false; 1758c2ecf20Sopenharmony_ci return (cache_validity & flags) != 0; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic bool nfs_check_cache_invalid_not_delegated(struct inode *inode, unsigned long flags) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci unsigned long cache_validity = READ_ONCE(NFS_I(inode)->cache_validity); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if ((cache_validity & flags) != 0) 1838c2ecf20Sopenharmony_ci return true; 1848c2ecf20Sopenharmony_ci if (nfs_attribute_timeout(inode)) 1858c2ecf20Sopenharmony_ci return true; 1868c2ecf20Sopenharmony_ci return false; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cibool nfs_check_cache_invalid(struct inode *inode, unsigned long flags) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) 1928c2ecf20Sopenharmony_ci return nfs_check_cache_invalid_delegated(inode, flags); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return nfs_check_cache_invalid_not_delegated(inode, flags); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_check_cache_invalid); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci#ifdef CONFIG_NFS_V4_2 1998c2ecf20Sopenharmony_cistatic bool nfs_has_xattr_cache(const struct nfs_inode *nfsi) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci return nfsi->xattr_cache != NULL; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci#else 2048c2ecf20Sopenharmony_cistatic bool nfs_has_xattr_cache(const struct nfs_inode *nfsi) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci return false; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci#endif 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void nfs_set_cache_invalid(struct inode *inode, unsigned long flags) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 2138c2ecf20Sopenharmony_ci bool have_delegation = NFS_PROTO(inode)->have_delegation(inode, FMODE_READ); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (have_delegation) { 2168c2ecf20Sopenharmony_ci if (!(flags & NFS_INO_REVAL_FORCED)) 2178c2ecf20Sopenharmony_ci flags &= ~NFS_INO_INVALID_OTHER; 2188c2ecf20Sopenharmony_ci flags &= ~(NFS_INO_INVALID_CHANGE 2198c2ecf20Sopenharmony_ci | NFS_INO_INVALID_SIZE 2208c2ecf20Sopenharmony_ci | NFS_INO_REVAL_PAGECACHE 2218c2ecf20Sopenharmony_ci | NFS_INO_INVALID_XATTR); 2228c2ecf20Sopenharmony_ci } else if (flags & NFS_INO_REVAL_PAGECACHE) 2238c2ecf20Sopenharmony_ci flags |= NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_SIZE; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (!nfs_has_xattr_cache(nfsi)) 2268c2ecf20Sopenharmony_ci flags &= ~NFS_INO_INVALID_XATTR; 2278c2ecf20Sopenharmony_ci if (inode->i_mapping->nrpages == 0) 2288c2ecf20Sopenharmony_ci flags &= ~(NFS_INO_INVALID_DATA|NFS_INO_DATA_INVAL_DEFER); 2298c2ecf20Sopenharmony_ci nfsi->cache_validity |= flags; 2308c2ecf20Sopenharmony_ci if (flags & NFS_INO_INVALID_DATA) 2318c2ecf20Sopenharmony_ci nfs_fscache_invalidate(inode); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* 2358c2ecf20Sopenharmony_ci * Invalidate the local caches 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_cistatic void nfs_zap_caches_locked(struct inode *inode) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 2408c2ecf20Sopenharmony_ci int mode = inode->i_mode; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); 2458c2ecf20Sopenharmony_ci nfsi->attrtimeo_timestamp = jiffies; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); 2488c2ecf20Sopenharmony_ci if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { 2498c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR 2508c2ecf20Sopenharmony_ci | NFS_INO_INVALID_DATA 2518c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACCESS 2528c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACL 2538c2ecf20Sopenharmony_ci | NFS_INO_INVALID_XATTR 2548c2ecf20Sopenharmony_ci | NFS_INO_REVAL_PAGECACHE); 2558c2ecf20Sopenharmony_ci } else 2568c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATTR 2578c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACCESS 2588c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACL 2598c2ecf20Sopenharmony_ci | NFS_INO_INVALID_XATTR 2608c2ecf20Sopenharmony_ci | NFS_INO_REVAL_PAGECACHE); 2618c2ecf20Sopenharmony_ci nfs_zap_label_cache_locked(nfsi); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_civoid nfs_zap_caches(struct inode *inode) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 2678c2ecf20Sopenharmony_ci nfs_zap_caches_locked(inode); 2688c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_civoid nfs_zap_mapping(struct inode *inode, struct address_space *mapping) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci if (mapping->nrpages != 0) { 2748c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 2758c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA); 2768c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_civoid nfs_zap_acl_cache(struct inode *inode) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci void (*clear_acl_cache)(struct inode *); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci clear_acl_cache = NFS_PROTO(inode)->clear_acl_cache; 2858c2ecf20Sopenharmony_ci if (clear_acl_cache != NULL) 2868c2ecf20Sopenharmony_ci clear_acl_cache(inode); 2878c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 2888c2ecf20Sopenharmony_ci NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_ACL; 2898c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_zap_acl_cache); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_civoid nfs_invalidate_atime(struct inode *inode) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 2968c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME); 2978c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_invalidate_atime); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/* 3028c2ecf20Sopenharmony_ci * Invalidate, but do not unhash, the inode. 3038c2ecf20Sopenharmony_ci * NB: must be called with inode->i_lock held! 3048c2ecf20Sopenharmony_ci */ 3058c2ecf20Sopenharmony_cistatic void nfs_set_inode_stale_locked(struct inode *inode) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); 3088c2ecf20Sopenharmony_ci nfs_zap_caches_locked(inode); 3098c2ecf20Sopenharmony_ci trace_nfs_set_inode_stale(inode); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_civoid nfs_set_inode_stale(struct inode *inode) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 3158c2ecf20Sopenharmony_ci nfs_set_inode_stale_locked(inode); 3168c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistruct nfs_find_desc { 3208c2ecf20Sopenharmony_ci struct nfs_fh *fh; 3218c2ecf20Sopenharmony_ci struct nfs_fattr *fattr; 3228c2ecf20Sopenharmony_ci}; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci/* 3258c2ecf20Sopenharmony_ci * In NFSv3 we can have 64bit inode numbers. In order to support 3268c2ecf20Sopenharmony_ci * this, and re-exported directories (also seen in NFSv2) 3278c2ecf20Sopenharmony_ci * we are forced to allow 2 different inodes to have the same 3288c2ecf20Sopenharmony_ci * i_ino. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_cistatic int 3318c2ecf20Sopenharmony_cinfs_find_actor(struct inode *inode, void *opaque) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque; 3348c2ecf20Sopenharmony_ci struct nfs_fh *fh = desc->fh; 3358c2ecf20Sopenharmony_ci struct nfs_fattr *fattr = desc->fattr; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (NFS_FILEID(inode) != fattr->fileid) 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_ci if (inode_wrong_type(inode, fattr->mode)) 3408c2ecf20Sopenharmony_ci return 0; 3418c2ecf20Sopenharmony_ci if (nfs_compare_fh(NFS_FH(inode), fh)) 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci if (is_bad_inode(inode) || NFS_STALE(inode)) 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci return 1; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int 3498c2ecf20Sopenharmony_cinfs_init_locked(struct inode *inode, void *opaque) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque; 3528c2ecf20Sopenharmony_ci struct nfs_fattr *fattr = desc->fattr; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci set_nfs_fileid(inode, fattr->fileid); 3558c2ecf20Sopenharmony_ci inode->i_mode = fattr->mode; 3568c2ecf20Sopenharmony_ci nfs_copy_fh(NFS_FH(inode), desc->fh); 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci#ifdef CONFIG_NFS_V4_SECURITY_LABEL 3618c2ecf20Sopenharmony_cistatic void nfs_clear_label_invalid(struct inode *inode) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 3648c2ecf20Sopenharmony_ci NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_LABEL; 3658c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_civoid nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, 3698c2ecf20Sopenharmony_ci struct nfs4_label *label) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci int error; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (label == NULL) 3748c2ecf20Sopenharmony_ci return; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL) && inode->i_security) { 3778c2ecf20Sopenharmony_ci error = security_inode_notifysecctx(inode, label->label, 3788c2ecf20Sopenharmony_ci label->len); 3798c2ecf20Sopenharmony_ci if (error) 3808c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() %s %d " 3818c2ecf20Sopenharmony_ci "security_inode_notifysecctx() %d\n", 3828c2ecf20Sopenharmony_ci __func__, 3838c2ecf20Sopenharmony_ci (char *)label->label, 3848c2ecf20Sopenharmony_ci label->len, error); 3858c2ecf20Sopenharmony_ci nfs_clear_label_invalid(inode); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistruct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct nfs4_label *label = NULL; 3928c2ecf20Sopenharmony_ci int minor_version = server->nfs_client->cl_minorversion; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (minor_version < 2) 3958c2ecf20Sopenharmony_ci return label; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (!(server->caps & NFS_CAP_SECURITY_LABEL)) 3988c2ecf20Sopenharmony_ci return label; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci label = kzalloc(sizeof(struct nfs4_label), flags); 4018c2ecf20Sopenharmony_ci if (label == NULL) 4028c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci label->label = kzalloc(NFS4_MAXLABELLEN, flags); 4058c2ecf20Sopenharmony_ci if (label->label == NULL) { 4068c2ecf20Sopenharmony_ci kfree(label); 4078c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci label->len = NFS4_MAXLABELLEN; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return label; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs4_label_alloc); 4148c2ecf20Sopenharmony_ci#else 4158c2ecf20Sopenharmony_civoid nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, 4168c2ecf20Sopenharmony_ci struct nfs4_label *label) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci#endif 4208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_setsecurity); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci/* Search for inode identified by fh, fileid and i_mode in inode cache. */ 4238c2ecf20Sopenharmony_cistruct inode * 4248c2ecf20Sopenharmony_cinfs_ilookup(struct super_block *sb, struct nfs_fattr *fattr, struct nfs_fh *fh) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct nfs_find_desc desc = { 4278c2ecf20Sopenharmony_ci .fh = fh, 4288c2ecf20Sopenharmony_ci .fattr = fattr, 4298c2ecf20Sopenharmony_ci }; 4308c2ecf20Sopenharmony_ci struct inode *inode; 4318c2ecf20Sopenharmony_ci unsigned long hash; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (!(fattr->valid & NFS_ATTR_FATTR_FILEID) || 4348c2ecf20Sopenharmony_ci !(fattr->valid & NFS_ATTR_FATTR_TYPE)) 4358c2ecf20Sopenharmony_ci return NULL; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci hash = nfs_fattr_to_ino_t(fattr); 4388c2ecf20Sopenharmony_ci inode = ilookup5(sb, hash, nfs_find_actor, &desc); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci dprintk("%s: returning %p\n", __func__, inode); 4418c2ecf20Sopenharmony_ci return inode; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci/* 4458c2ecf20Sopenharmony_ci * This is our front-end to iget that looks up inodes by file handle 4468c2ecf20Sopenharmony_ci * instead of inode number. 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_cistruct inode * 4498c2ecf20Sopenharmony_cinfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, struct nfs4_label *label) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct nfs_find_desc desc = { 4528c2ecf20Sopenharmony_ci .fh = fh, 4538c2ecf20Sopenharmony_ci .fattr = fattr 4548c2ecf20Sopenharmony_ci }; 4558c2ecf20Sopenharmony_ci struct inode *inode = ERR_PTR(-ENOENT); 4568c2ecf20Sopenharmony_ci unsigned long hash; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci nfs_attr_check_mountpoint(sb, fattr); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (nfs_attr_use_mounted_on_fileid(fattr)) 4618c2ecf20Sopenharmony_ci fattr->fileid = fattr->mounted_on_fileid; 4628c2ecf20Sopenharmony_ci else if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0) 4638c2ecf20Sopenharmony_ci goto out_no_inode; 4648c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0) 4658c2ecf20Sopenharmony_ci goto out_no_inode; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci hash = nfs_fattr_to_ino_t(fattr); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc); 4708c2ecf20Sopenharmony_ci if (inode == NULL) { 4718c2ecf20Sopenharmony_ci inode = ERR_PTR(-ENOMEM); 4728c2ecf20Sopenharmony_ci goto out_no_inode; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (inode->i_state & I_NEW) { 4768c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 4778c2ecf20Sopenharmony_ci unsigned long now = jiffies; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* We set i_ino for the few things that still rely on it, 4808c2ecf20Sopenharmony_ci * such as stat(2) */ 4818c2ecf20Sopenharmony_ci inode->i_ino = hash; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* We can't support update_atime(), since the server will reset it */ 4848c2ecf20Sopenharmony_ci inode->i_flags |= S_NOATIME|S_NOCMTIME; 4858c2ecf20Sopenharmony_ci inode->i_mode = fattr->mode; 4868c2ecf20Sopenharmony_ci nfsi->cache_validity = 0; 4878c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_MODE) == 0 4888c2ecf20Sopenharmony_ci && nfs_server_capable(inode, NFS_CAP_MODE)) 4898c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER); 4908c2ecf20Sopenharmony_ci /* Why so? Because we want revalidate for devices/FIFOs, and 4918c2ecf20Sopenharmony_ci * that's precisely what we have in nfs_file_inode_operations. 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_ci inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops; 4948c2ecf20Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 4958c2ecf20Sopenharmony_ci inode->i_fop = NFS_SB(sb)->nfs_client->rpc_ops->file_ops; 4968c2ecf20Sopenharmony_ci inode->i_data.a_ops = &nfs_file_aops; 4978c2ecf20Sopenharmony_ci } else if (S_ISDIR(inode->i_mode)) { 4988c2ecf20Sopenharmony_ci inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops; 4998c2ecf20Sopenharmony_ci inode->i_fop = &nfs_dir_operations; 5008c2ecf20Sopenharmony_ci inode->i_data.a_ops = &nfs_dir_aops; 5018c2ecf20Sopenharmony_ci /* Deal with crossing mountpoints */ 5028c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT || 5038c2ecf20Sopenharmony_ci fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { 5048c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) 5058c2ecf20Sopenharmony_ci inode->i_op = &nfs_referral_inode_operations; 5068c2ecf20Sopenharmony_ci else 5078c2ecf20Sopenharmony_ci inode->i_op = &nfs_mountpoint_inode_operations; 5088c2ecf20Sopenharmony_ci inode->i_fop = NULL; 5098c2ecf20Sopenharmony_ci inode->i_flags |= S_AUTOMOUNT; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci } else if (S_ISLNK(inode->i_mode)) { 5128c2ecf20Sopenharmony_ci inode->i_op = &nfs_symlink_inode_operations; 5138c2ecf20Sopenharmony_ci inode_nohighmem(inode); 5148c2ecf20Sopenharmony_ci } else 5158c2ecf20Sopenharmony_ci init_special_inode(inode, inode->i_mode, fattr->rdev); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci memset(&inode->i_atime, 0, sizeof(inode->i_atime)); 5188c2ecf20Sopenharmony_ci memset(&inode->i_mtime, 0, sizeof(inode->i_mtime)); 5198c2ecf20Sopenharmony_ci memset(&inode->i_ctime, 0, sizeof(inode->i_ctime)); 5208c2ecf20Sopenharmony_ci inode_set_iversion_raw(inode, 0); 5218c2ecf20Sopenharmony_ci inode->i_size = 0; 5228c2ecf20Sopenharmony_ci clear_nlink(inode); 5238c2ecf20Sopenharmony_ci inode->i_uid = make_kuid(&init_user_ns, -2); 5248c2ecf20Sopenharmony_ci inode->i_gid = make_kgid(&init_user_ns, -2); 5258c2ecf20Sopenharmony_ci inode->i_blocks = 0; 5268c2ecf20Sopenharmony_ci memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); 5278c2ecf20Sopenharmony_ci nfsi->write_io = 0; 5288c2ecf20Sopenharmony_ci nfsi->read_io = 0; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci nfsi->read_cache_jiffies = fattr->time_start; 5318c2ecf20Sopenharmony_ci nfsi->attr_gencount = fattr->gencount; 5328c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_ATIME) 5338c2ecf20Sopenharmony_ci inode->i_atime = fattr->atime; 5348c2ecf20Sopenharmony_ci else if (nfs_server_capable(inode, NFS_CAP_ATIME)) 5358c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME); 5368c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MTIME) 5378c2ecf20Sopenharmony_ci inode->i_mtime = fattr->mtime; 5388c2ecf20Sopenharmony_ci else if (nfs_server_capable(inode, NFS_CAP_MTIME)) 5398c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME); 5408c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CTIME) 5418c2ecf20Sopenharmony_ci inode->i_ctime = fattr->ctime; 5428c2ecf20Sopenharmony_ci else if (nfs_server_capable(inode, NFS_CAP_CTIME)) 5438c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_CTIME); 5448c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CHANGE) 5458c2ecf20Sopenharmony_ci inode_set_iversion_raw(inode, fattr->change_attr); 5468c2ecf20Sopenharmony_ci else 5478c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE); 5488c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_SIZE) 5498c2ecf20Sopenharmony_ci inode->i_size = nfs_size_to_loff_t(fattr->size); 5508c2ecf20Sopenharmony_ci else 5518c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_SIZE); 5528c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_NLINK) 5538c2ecf20Sopenharmony_ci set_nlink(inode, fattr->nlink); 5548c2ecf20Sopenharmony_ci else if (nfs_server_capable(inode, NFS_CAP_NLINK)) 5558c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER); 5568c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_OWNER) 5578c2ecf20Sopenharmony_ci inode->i_uid = fattr->uid; 5588c2ecf20Sopenharmony_ci else if (nfs_server_capable(inode, NFS_CAP_OWNER)) 5598c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER); 5608c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_GROUP) 5618c2ecf20Sopenharmony_ci inode->i_gid = fattr->gid; 5628c2ecf20Sopenharmony_ci else if (nfs_server_capable(inode, NFS_CAP_OWNER_GROUP)) 5638c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_OTHER); 5648c2ecf20Sopenharmony_ci if (nfs_server_capable(inode, NFS_CAP_XATTR)) 5658c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_XATTR); 5668c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) 5678c2ecf20Sopenharmony_ci inode->i_blocks = fattr->du.nfs2.blocks; 5688c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { 5698c2ecf20Sopenharmony_ci /* 5708c2ecf20Sopenharmony_ci * report the blocks in 512byte units 5718c2ecf20Sopenharmony_ci */ 5728c2ecf20Sopenharmony_ci inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (nfsi->cache_validity != 0) 5768c2ecf20Sopenharmony_ci nfsi->cache_validity |= NFS_INO_REVAL_FORCED; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci nfs_setsecurity(inode, fattr, label); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); 5818c2ecf20Sopenharmony_ci nfsi->attrtimeo_timestamp = now; 5828c2ecf20Sopenharmony_ci nfsi->access_cache = RB_ROOT; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci nfs_fscache_init_inode(inode); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci unlock_new_inode(inode); 5878c2ecf20Sopenharmony_ci } else { 5888c2ecf20Sopenharmony_ci int err = nfs_refresh_inode(inode, fattr); 5898c2ecf20Sopenharmony_ci if (err < 0) { 5908c2ecf20Sopenharmony_ci iput(inode); 5918c2ecf20Sopenharmony_ci inode = ERR_PTR(err); 5928c2ecf20Sopenharmony_ci goto out_no_inode; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci dprintk("NFS: nfs_fhget(%s/%Lu fh_crc=0x%08x ct=%d)\n", 5968c2ecf20Sopenharmony_ci inode->i_sb->s_id, 5978c2ecf20Sopenharmony_ci (unsigned long long)NFS_FILEID(inode), 5988c2ecf20Sopenharmony_ci nfs_display_fhandle_hash(fh), 5998c2ecf20Sopenharmony_ci atomic_read(&inode->i_count)); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ciout: 6028c2ecf20Sopenharmony_ci return inode; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ciout_no_inode: 6058c2ecf20Sopenharmony_ci dprintk("nfs_fhget: iget failed with error %ld\n", PTR_ERR(inode)); 6068c2ecf20Sopenharmony_ci goto out; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_fhget); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_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) 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ciint 6138c2ecf20Sopenharmony_cinfs_setattr(struct dentry *dentry, struct iattr *attr) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 6168c2ecf20Sopenharmony_ci struct nfs_fattr *fattr; 6178c2ecf20Sopenharmony_ci int error = 0; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_VFSSETATTR); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* skip mode change if it's just for clearing setuid/setgid */ 6228c2ecf20Sopenharmony_ci if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) 6238c2ecf20Sopenharmony_ci attr->ia_valid &= ~ATTR_MODE; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (attr->ia_valid & ATTR_SIZE) { 6268c2ecf20Sopenharmony_ci BUG_ON(!S_ISREG(inode->i_mode)); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci error = inode_newsize_ok(inode, attr->ia_size); 6298c2ecf20Sopenharmony_ci if (error) 6308c2ecf20Sopenharmony_ci return error; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (attr->ia_size == i_size_read(inode)) 6338c2ecf20Sopenharmony_ci attr->ia_valid &= ~ATTR_SIZE; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci /* Optimization: if the end result is no change, don't RPC */ 6378c2ecf20Sopenharmony_ci attr->ia_valid &= NFS_VALID_ATTRS; 6388c2ecf20Sopenharmony_ci if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0) 6398c2ecf20Sopenharmony_ci return 0; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci trace_nfs_setattr_enter(inode); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* Write all dirty data */ 6448c2ecf20Sopenharmony_ci if (S_ISREG(inode->i_mode)) 6458c2ecf20Sopenharmony_ci nfs_sync_inode(inode); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci fattr = nfs_alloc_fattr(); 6488c2ecf20Sopenharmony_ci if (fattr == NULL) { 6498c2ecf20Sopenharmony_ci error = -ENOMEM; 6508c2ecf20Sopenharmony_ci goto out; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); 6548c2ecf20Sopenharmony_ci if (error == 0) 6558c2ecf20Sopenharmony_ci error = nfs_refresh_inode(inode, fattr); 6568c2ecf20Sopenharmony_ci nfs_free_fattr(fattr); 6578c2ecf20Sopenharmony_ciout: 6588c2ecf20Sopenharmony_ci trace_nfs_setattr_exit(inode, error); 6598c2ecf20Sopenharmony_ci return error; 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_setattr); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci/** 6648c2ecf20Sopenharmony_ci * nfs_vmtruncate - unmap mappings "freed" by truncate() syscall 6658c2ecf20Sopenharmony_ci * @inode: inode of the file used 6668c2ecf20Sopenharmony_ci * @offset: file offset to start truncating 6678c2ecf20Sopenharmony_ci * 6688c2ecf20Sopenharmony_ci * This is a copy of the common vmtruncate, but with the locking 6698c2ecf20Sopenharmony_ci * corrected to take into account the fact that NFS requires 6708c2ecf20Sopenharmony_ci * inode->i_size to be updated under the inode->i_lock. 6718c2ecf20Sopenharmony_ci * Note: must be called with inode->i_lock held! 6728c2ecf20Sopenharmony_ci */ 6738c2ecf20Sopenharmony_cistatic int nfs_vmtruncate(struct inode * inode, loff_t offset) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci int err; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci err = inode_newsize_ok(inode, offset); 6788c2ecf20Sopenharmony_ci if (err) 6798c2ecf20Sopenharmony_ci goto out; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci i_size_write(inode, offset); 6828c2ecf20Sopenharmony_ci /* Optimisation */ 6838c2ecf20Sopenharmony_ci if (offset == 0) 6848c2ecf20Sopenharmony_ci NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_DATA | 6858c2ecf20Sopenharmony_ci NFS_INO_DATA_INVAL_DEFER); 6868c2ecf20Sopenharmony_ci NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_SIZE; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 6898c2ecf20Sopenharmony_ci truncate_pagecache(inode, offset); 6908c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 6918c2ecf20Sopenharmony_ciout: 6928c2ecf20Sopenharmony_ci return err; 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci/** 6968c2ecf20Sopenharmony_ci * nfs_setattr_update_inode - Update inode metadata after a setattr call. 6978c2ecf20Sopenharmony_ci * @inode: pointer to struct inode 6988c2ecf20Sopenharmony_ci * @attr: pointer to struct iattr 6998c2ecf20Sopenharmony_ci * @fattr: pointer to struct nfs_fattr 7008c2ecf20Sopenharmony_ci * 7018c2ecf20Sopenharmony_ci * Note: we do this in the *proc.c in order to ensure that 7028c2ecf20Sopenharmony_ci * it works for things like exclusive creates too. 7038c2ecf20Sopenharmony_ci */ 7048c2ecf20Sopenharmony_civoid nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, 7058c2ecf20Sopenharmony_ci struct nfs_fattr *fattr) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci /* Barrier: bump the attribute generation count. */ 7088c2ecf20Sopenharmony_ci nfs_fattr_set_barrier(fattr); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 7118c2ecf20Sopenharmony_ci NFS_I(inode)->attr_gencount = fattr->gencount; 7128c2ecf20Sopenharmony_ci if ((attr->ia_valid & ATTR_SIZE) != 0) { 7138c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME); 7148c2ecf20Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC); 7158c2ecf20Sopenharmony_ci nfs_vmtruncate(inode, attr->ia_size); 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) { 7188c2ecf20Sopenharmony_ci NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_CTIME; 7198c2ecf20Sopenharmony_ci if ((attr->ia_valid & ATTR_MODE) != 0) { 7208c2ecf20Sopenharmony_ci int mode = attr->ia_mode & S_IALLUGO; 7218c2ecf20Sopenharmony_ci mode |= inode->i_mode & ~S_IALLUGO; 7228c2ecf20Sopenharmony_ci inode->i_mode = mode; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci if ((attr->ia_valid & ATTR_UID) != 0) 7258c2ecf20Sopenharmony_ci inode->i_uid = attr->ia_uid; 7268c2ecf20Sopenharmony_ci if ((attr->ia_valid & ATTR_GID) != 0) 7278c2ecf20Sopenharmony_ci inode->i_gid = attr->ia_gid; 7288c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CTIME) 7298c2ecf20Sopenharmony_ci inode->i_ctime = fattr->ctime; 7308c2ecf20Sopenharmony_ci else 7318c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE 7328c2ecf20Sopenharmony_ci | NFS_INO_INVALID_CTIME); 7338c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_ACCESS 7348c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACL); 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci if (attr->ia_valid & (ATTR_ATIME_SET|ATTR_ATIME)) { 7378c2ecf20Sopenharmony_ci NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_ATIME 7388c2ecf20Sopenharmony_ci | NFS_INO_INVALID_CTIME); 7398c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_ATIME) 7408c2ecf20Sopenharmony_ci inode->i_atime = fattr->atime; 7418c2ecf20Sopenharmony_ci else if (attr->ia_valid & ATTR_ATIME_SET) 7428c2ecf20Sopenharmony_ci inode->i_atime = attr->ia_atime; 7438c2ecf20Sopenharmony_ci else 7448c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_ATIME); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CTIME) 7478c2ecf20Sopenharmony_ci inode->i_ctime = fattr->ctime; 7488c2ecf20Sopenharmony_ci else 7498c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE 7508c2ecf20Sopenharmony_ci | NFS_INO_INVALID_CTIME); 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci if (attr->ia_valid & (ATTR_MTIME_SET|ATTR_MTIME)) { 7538c2ecf20Sopenharmony_ci NFS_I(inode)->cache_validity &= ~(NFS_INO_INVALID_MTIME 7548c2ecf20Sopenharmony_ci | NFS_INO_INVALID_CTIME); 7558c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MTIME) 7568c2ecf20Sopenharmony_ci inode->i_mtime = fattr->mtime; 7578c2ecf20Sopenharmony_ci else if (attr->ia_valid & ATTR_MTIME_SET) 7588c2ecf20Sopenharmony_ci inode->i_mtime = attr->ia_mtime; 7598c2ecf20Sopenharmony_ci else 7608c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_MTIME); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CTIME) 7638c2ecf20Sopenharmony_ci inode->i_ctime = fattr->ctime; 7648c2ecf20Sopenharmony_ci else 7658c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_CHANGE 7668c2ecf20Sopenharmony_ci | NFS_INO_INVALID_CTIME); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci if (fattr->valid) 7698c2ecf20Sopenharmony_ci nfs_update_inode(inode, fattr); 7708c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_setattr_update_inode); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic void nfs_readdirplus_parent_cache_miss(struct dentry *dentry) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci struct dentry *parent; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (!nfs_server_capable(d_inode(dentry), NFS_CAP_READDIRPLUS)) 7798c2ecf20Sopenharmony_ci return; 7808c2ecf20Sopenharmony_ci parent = dget_parent(dentry); 7818c2ecf20Sopenharmony_ci nfs_force_use_readdirplus(d_inode(parent)); 7828c2ecf20Sopenharmony_ci dput(parent); 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic void nfs_readdirplus_parent_cache_hit(struct dentry *dentry) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci struct dentry *parent; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (!nfs_server_capable(d_inode(dentry), NFS_CAP_READDIRPLUS)) 7908c2ecf20Sopenharmony_ci return; 7918c2ecf20Sopenharmony_ci parent = dget_parent(dentry); 7928c2ecf20Sopenharmony_ci nfs_advise_use_readdirplus(d_inode(parent)); 7938c2ecf20Sopenharmony_ci dput(parent); 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic bool nfs_need_revalidate_inode(struct inode *inode) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci if (NFS_I(inode)->cache_validity & 7998c2ecf20Sopenharmony_ci (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) 8008c2ecf20Sopenharmony_ci return true; 8018c2ecf20Sopenharmony_ci if (nfs_attribute_cache_expired(inode)) 8028c2ecf20Sopenharmony_ci return true; 8038c2ecf20Sopenharmony_ci return false; 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ciint nfs_getattr(const struct path *path, struct kstat *stat, 8078c2ecf20Sopenharmony_ci u32 request_mask, unsigned int query_flags) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci struct inode *inode = d_inode(path->dentry); 8108c2ecf20Sopenharmony_ci struct nfs_server *server = NFS_SERVER(inode); 8118c2ecf20Sopenharmony_ci unsigned long cache_validity; 8128c2ecf20Sopenharmony_ci int err = 0; 8138c2ecf20Sopenharmony_ci bool force_sync = query_flags & AT_STATX_FORCE_SYNC; 8148c2ecf20Sopenharmony_ci bool do_update = false; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci trace_nfs_getattr_enter(inode); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci if ((query_flags & AT_STATX_DONT_SYNC) && !force_sync) { 8198c2ecf20Sopenharmony_ci nfs_readdirplus_parent_cache_hit(path->dentry); 8208c2ecf20Sopenharmony_ci goto out_no_update; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* Flush out writes to the server in order to update c/mtime. */ 8248c2ecf20Sopenharmony_ci if ((request_mask & (STATX_CTIME | STATX_MTIME)) && 8258c2ecf20Sopenharmony_ci S_ISREG(inode->i_mode)) 8268c2ecf20Sopenharmony_ci filemap_write_and_wait(inode->i_mapping); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* 8298c2ecf20Sopenharmony_ci * We may force a getattr if the user cares about atime. 8308c2ecf20Sopenharmony_ci * 8318c2ecf20Sopenharmony_ci * Note that we only have to check the vfsmount flags here: 8328c2ecf20Sopenharmony_ci * - NFS always sets S_NOATIME by so checking it would give a 8338c2ecf20Sopenharmony_ci * bogus result 8348c2ecf20Sopenharmony_ci * - NFS never sets SB_NOATIME or SB_NODIRATIME so there is 8358c2ecf20Sopenharmony_ci * no point in checking those. 8368c2ecf20Sopenharmony_ci */ 8378c2ecf20Sopenharmony_ci if ((path->mnt->mnt_flags & MNT_NOATIME) || 8388c2ecf20Sopenharmony_ci ((path->mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))) 8398c2ecf20Sopenharmony_ci request_mask &= ~STATX_ATIME; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* Is the user requesting attributes that might need revalidation? */ 8428c2ecf20Sopenharmony_ci if (!(request_mask & (STATX_MODE|STATX_NLINK|STATX_ATIME|STATX_CTIME| 8438c2ecf20Sopenharmony_ci STATX_MTIME|STATX_UID|STATX_GID| 8448c2ecf20Sopenharmony_ci STATX_SIZE|STATX_BLOCKS))) 8458c2ecf20Sopenharmony_ci goto out_no_revalidate; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* Check whether the cached attributes are stale */ 8488c2ecf20Sopenharmony_ci do_update |= force_sync || nfs_attribute_cache_expired(inode); 8498c2ecf20Sopenharmony_ci cache_validity = READ_ONCE(NFS_I(inode)->cache_validity); 8508c2ecf20Sopenharmony_ci do_update |= cache_validity & 8518c2ecf20Sopenharmony_ci (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL); 8528c2ecf20Sopenharmony_ci if (request_mask & STATX_ATIME) 8538c2ecf20Sopenharmony_ci do_update |= cache_validity & NFS_INO_INVALID_ATIME; 8548c2ecf20Sopenharmony_ci if (request_mask & (STATX_CTIME|STATX_MTIME)) 8558c2ecf20Sopenharmony_ci do_update |= cache_validity & NFS_INO_REVAL_PAGECACHE; 8568c2ecf20Sopenharmony_ci if (request_mask & STATX_BLOCKS) 8578c2ecf20Sopenharmony_ci do_update |= cache_validity & NFS_INO_INVALID_BLOCKS; 8588c2ecf20Sopenharmony_ci if (do_update) { 8598c2ecf20Sopenharmony_ci /* Update the attribute cache */ 8608c2ecf20Sopenharmony_ci if (!(server->flags & NFS_MOUNT_NOAC)) 8618c2ecf20Sopenharmony_ci nfs_readdirplus_parent_cache_miss(path->dentry); 8628c2ecf20Sopenharmony_ci else 8638c2ecf20Sopenharmony_ci nfs_readdirplus_parent_cache_hit(path->dentry); 8648c2ecf20Sopenharmony_ci err = __nfs_revalidate_inode(server, inode); 8658c2ecf20Sopenharmony_ci if (err) 8668c2ecf20Sopenharmony_ci goto out; 8678c2ecf20Sopenharmony_ci } else 8688c2ecf20Sopenharmony_ci nfs_readdirplus_parent_cache_hit(path->dentry); 8698c2ecf20Sopenharmony_ciout_no_revalidate: 8708c2ecf20Sopenharmony_ci /* Only return attributes that were revalidated. */ 8718c2ecf20Sopenharmony_ci stat->result_mask &= request_mask; 8728c2ecf20Sopenharmony_ciout_no_update: 8738c2ecf20Sopenharmony_ci generic_fillattr(inode, stat); 8748c2ecf20Sopenharmony_ci stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode)); 8758c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 8768c2ecf20Sopenharmony_ci stat->blksize = NFS_SERVER(inode)->dtsize; 8778c2ecf20Sopenharmony_ciout: 8788c2ecf20Sopenharmony_ci trace_nfs_getattr_exit(inode, err); 8798c2ecf20Sopenharmony_ci return err; 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_getattr); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic void nfs_init_lock_context(struct nfs_lock_context *l_ctx) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci refcount_set(&l_ctx->count, 1); 8868c2ecf20Sopenharmony_ci l_ctx->lockowner = current->files; 8878c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&l_ctx->list); 8888c2ecf20Sopenharmony_ci atomic_set(&l_ctx->io_count, 0); 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx) 8928c2ecf20Sopenharmony_ci{ 8938c2ecf20Sopenharmony_ci struct nfs_lock_context *pos; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci list_for_each_entry_rcu(pos, &ctx->lock_context.list, list) { 8968c2ecf20Sopenharmony_ci if (pos->lockowner != current->files) 8978c2ecf20Sopenharmony_ci continue; 8988c2ecf20Sopenharmony_ci if (refcount_inc_not_zero(&pos->count)) 8998c2ecf20Sopenharmony_ci return pos; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci return NULL; 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistruct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx) 9058c2ecf20Sopenharmony_ci{ 9068c2ecf20Sopenharmony_ci struct nfs_lock_context *res, *new = NULL; 9078c2ecf20Sopenharmony_ci struct inode *inode = d_inode(ctx->dentry); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci rcu_read_lock(); 9108c2ecf20Sopenharmony_ci res = __nfs_find_lock_context(ctx); 9118c2ecf20Sopenharmony_ci rcu_read_unlock(); 9128c2ecf20Sopenharmony_ci if (res == NULL) { 9138c2ecf20Sopenharmony_ci new = kmalloc(sizeof(*new), GFP_KERNEL); 9148c2ecf20Sopenharmony_ci if (new == NULL) 9158c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 9168c2ecf20Sopenharmony_ci nfs_init_lock_context(new); 9178c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 9188c2ecf20Sopenharmony_ci res = __nfs_find_lock_context(ctx); 9198c2ecf20Sopenharmony_ci if (res == NULL) { 9208c2ecf20Sopenharmony_ci new->open_context = get_nfs_open_context(ctx); 9218c2ecf20Sopenharmony_ci if (new->open_context) { 9228c2ecf20Sopenharmony_ci list_add_tail_rcu(&new->list, 9238c2ecf20Sopenharmony_ci &ctx->lock_context.list); 9248c2ecf20Sopenharmony_ci res = new; 9258c2ecf20Sopenharmony_ci new = NULL; 9268c2ecf20Sopenharmony_ci } else 9278c2ecf20Sopenharmony_ci res = ERR_PTR(-EBADF); 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 9308c2ecf20Sopenharmony_ci kfree(new); 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci return res; 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_get_lock_context); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_civoid nfs_put_lock_context(struct nfs_lock_context *l_ctx) 9378c2ecf20Sopenharmony_ci{ 9388c2ecf20Sopenharmony_ci struct nfs_open_context *ctx = l_ctx->open_context; 9398c2ecf20Sopenharmony_ci struct inode *inode = d_inode(ctx->dentry); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci if (!refcount_dec_and_lock(&l_ctx->count, &inode->i_lock)) 9428c2ecf20Sopenharmony_ci return; 9438c2ecf20Sopenharmony_ci list_del_rcu(&l_ctx->list); 9448c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 9458c2ecf20Sopenharmony_ci put_nfs_open_context(ctx); 9468c2ecf20Sopenharmony_ci kfree_rcu(l_ctx, rcu_head); 9478c2ecf20Sopenharmony_ci} 9488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_put_lock_context); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci/** 9518c2ecf20Sopenharmony_ci * nfs_close_context - Common close_context() routine NFSv2/v3 9528c2ecf20Sopenharmony_ci * @ctx: pointer to context 9538c2ecf20Sopenharmony_ci * @is_sync: is this a synchronous close 9548c2ecf20Sopenharmony_ci * 9558c2ecf20Sopenharmony_ci * Ensure that the attributes are up to date if we're mounted 9568c2ecf20Sopenharmony_ci * with close-to-open semantics and we have cached data that will 9578c2ecf20Sopenharmony_ci * need to be revalidated on open. 9588c2ecf20Sopenharmony_ci */ 9598c2ecf20Sopenharmony_civoid nfs_close_context(struct nfs_open_context *ctx, int is_sync) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci struct nfs_inode *nfsi; 9628c2ecf20Sopenharmony_ci struct inode *inode; 9638c2ecf20Sopenharmony_ci struct nfs_server *server; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (!(ctx->mode & FMODE_WRITE)) 9668c2ecf20Sopenharmony_ci return; 9678c2ecf20Sopenharmony_ci if (!is_sync) 9688c2ecf20Sopenharmony_ci return; 9698c2ecf20Sopenharmony_ci inode = d_inode(ctx->dentry); 9708c2ecf20Sopenharmony_ci if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) 9718c2ecf20Sopenharmony_ci return; 9728c2ecf20Sopenharmony_ci nfsi = NFS_I(inode); 9738c2ecf20Sopenharmony_ci if (inode->i_mapping->nrpages == 0) 9748c2ecf20Sopenharmony_ci return; 9758c2ecf20Sopenharmony_ci if (nfsi->cache_validity & NFS_INO_INVALID_DATA) 9768c2ecf20Sopenharmony_ci return; 9778c2ecf20Sopenharmony_ci if (!list_empty(&nfsi->open_files)) 9788c2ecf20Sopenharmony_ci return; 9798c2ecf20Sopenharmony_ci server = NFS_SERVER(inode); 9808c2ecf20Sopenharmony_ci if (server->flags & NFS_MOUNT_NOCTO) 9818c2ecf20Sopenharmony_ci return; 9828c2ecf20Sopenharmony_ci nfs_revalidate_inode(server, inode); 9838c2ecf20Sopenharmony_ci} 9848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_close_context); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistruct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, 9878c2ecf20Sopenharmony_ci fmode_t f_mode, 9888c2ecf20Sopenharmony_ci struct file *filp) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct nfs_open_context *ctx; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); 9938c2ecf20Sopenharmony_ci if (!ctx) 9948c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 9958c2ecf20Sopenharmony_ci nfs_sb_active(dentry->d_sb); 9968c2ecf20Sopenharmony_ci ctx->dentry = dget(dentry); 9978c2ecf20Sopenharmony_ci if (filp) 9988c2ecf20Sopenharmony_ci ctx->cred = get_cred(filp->f_cred); 9998c2ecf20Sopenharmony_ci else 10008c2ecf20Sopenharmony_ci ctx->cred = get_current_cred(); 10018c2ecf20Sopenharmony_ci ctx->ll_cred = NULL; 10028c2ecf20Sopenharmony_ci ctx->state = NULL; 10038c2ecf20Sopenharmony_ci ctx->mode = f_mode; 10048c2ecf20Sopenharmony_ci ctx->flags = 0; 10058c2ecf20Sopenharmony_ci ctx->error = 0; 10068c2ecf20Sopenharmony_ci ctx->flock_owner = (fl_owner_t)filp; 10078c2ecf20Sopenharmony_ci nfs_init_lock_context(&ctx->lock_context); 10088c2ecf20Sopenharmony_ci ctx->lock_context.open_context = ctx; 10098c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ctx->list); 10108c2ecf20Sopenharmony_ci ctx->mdsthreshold = NULL; 10118c2ecf20Sopenharmony_ci return ctx; 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(alloc_nfs_open_context); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cistruct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci if (ctx != NULL && refcount_inc_not_zero(&ctx->lock_context.count)) 10188c2ecf20Sopenharmony_ci return ctx; 10198c2ecf20Sopenharmony_ci return NULL; 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(get_nfs_open_context); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci struct inode *inode = d_inode(ctx->dentry); 10268c2ecf20Sopenharmony_ci struct super_block *sb = ctx->dentry->d_sb; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (!refcount_dec_and_test(&ctx->lock_context.count)) 10298c2ecf20Sopenharmony_ci return; 10308c2ecf20Sopenharmony_ci if (!list_empty(&ctx->list)) { 10318c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 10328c2ecf20Sopenharmony_ci list_del_rcu(&ctx->list); 10338c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci if (inode != NULL) 10368c2ecf20Sopenharmony_ci NFS_PROTO(inode)->close_context(ctx, is_sync); 10378c2ecf20Sopenharmony_ci put_cred(ctx->cred); 10388c2ecf20Sopenharmony_ci dput(ctx->dentry); 10398c2ecf20Sopenharmony_ci nfs_sb_deactive(sb); 10408c2ecf20Sopenharmony_ci put_rpccred(ctx->ll_cred); 10418c2ecf20Sopenharmony_ci kfree(ctx->mdsthreshold); 10428c2ecf20Sopenharmony_ci kfree_rcu(ctx, rcu_head); 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_civoid put_nfs_open_context(struct nfs_open_context *ctx) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci __put_nfs_open_context(ctx, 0); 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(put_nfs_open_context); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_cistatic void put_nfs_open_context_sync(struct nfs_open_context *ctx) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci __put_nfs_open_context(ctx, 1); 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci/* 10578c2ecf20Sopenharmony_ci * Ensure that mmap has a recent RPC credential for use when writing out 10588c2ecf20Sopenharmony_ci * shared pages 10598c2ecf20Sopenharmony_ci */ 10608c2ecf20Sopenharmony_civoid nfs_inode_attach_open_context(struct nfs_open_context *ctx) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci struct inode *inode = d_inode(ctx->dentry); 10638c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 10668c2ecf20Sopenharmony_ci if (list_empty(&nfsi->open_files) && 10678c2ecf20Sopenharmony_ci (nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER)) 10688c2ecf20Sopenharmony_ci nfsi->cache_validity |= NFS_INO_INVALID_DATA | 10698c2ecf20Sopenharmony_ci NFS_INO_REVAL_FORCED; 10708c2ecf20Sopenharmony_ci list_add_tail_rcu(&ctx->list, &nfsi->open_files); 10718c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_inode_attach_open_context); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_civoid nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci filp->private_data = get_nfs_open_context(ctx); 10788c2ecf20Sopenharmony_ci set_bit(NFS_CONTEXT_FILE_OPEN, &ctx->flags); 10798c2ecf20Sopenharmony_ci if (list_empty(&ctx->list)) 10808c2ecf20Sopenharmony_ci nfs_inode_attach_open_context(ctx); 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_file_set_open_context); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci/* 10858c2ecf20Sopenharmony_ci * Given an inode, search for an open context with the desired characteristics 10868c2ecf20Sopenharmony_ci */ 10878c2ecf20Sopenharmony_cistruct nfs_open_context *nfs_find_open_context(struct inode *inode, const struct cred *cred, fmode_t mode) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 10908c2ecf20Sopenharmony_ci struct nfs_open_context *pos, *ctx = NULL; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci rcu_read_lock(); 10938c2ecf20Sopenharmony_ci list_for_each_entry_rcu(pos, &nfsi->open_files, list) { 10948c2ecf20Sopenharmony_ci if (cred != NULL && cred_fscmp(pos->cred, cred) != 0) 10958c2ecf20Sopenharmony_ci continue; 10968c2ecf20Sopenharmony_ci if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode) 10978c2ecf20Sopenharmony_ci continue; 10988c2ecf20Sopenharmony_ci if (!test_bit(NFS_CONTEXT_FILE_OPEN, &pos->flags)) 10998c2ecf20Sopenharmony_ci continue; 11008c2ecf20Sopenharmony_ci ctx = get_nfs_open_context(pos); 11018c2ecf20Sopenharmony_ci if (ctx) 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci rcu_read_unlock(); 11058c2ecf20Sopenharmony_ci return ctx; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_civoid nfs_file_clear_open_context(struct file *filp) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci struct nfs_open_context *ctx = nfs_file_open_context(filp); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (ctx) { 11138c2ecf20Sopenharmony_ci struct inode *inode = d_inode(ctx->dentry); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci clear_bit(NFS_CONTEXT_FILE_OPEN, &ctx->flags); 11168c2ecf20Sopenharmony_ci /* 11178c2ecf20Sopenharmony_ci * We fatal error on write before. Try to writeback 11188c2ecf20Sopenharmony_ci * every page again. 11198c2ecf20Sopenharmony_ci */ 11208c2ecf20Sopenharmony_ci if (ctx->error < 0) 11218c2ecf20Sopenharmony_ci invalidate_inode_pages2(inode->i_mapping); 11228c2ecf20Sopenharmony_ci filp->private_data = NULL; 11238c2ecf20Sopenharmony_ci put_nfs_open_context_sync(ctx); 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci} 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci/* 11288c2ecf20Sopenharmony_ci * These allocate and release file read/write context information. 11298c2ecf20Sopenharmony_ci */ 11308c2ecf20Sopenharmony_ciint nfs_open(struct inode *inode, struct file *filp) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci struct nfs_open_context *ctx; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci ctx = alloc_nfs_open_context(file_dentry(filp), filp->f_mode, filp); 11358c2ecf20Sopenharmony_ci if (IS_ERR(ctx)) 11368c2ecf20Sopenharmony_ci return PTR_ERR(ctx); 11378c2ecf20Sopenharmony_ci nfs_file_set_open_context(filp, ctx); 11388c2ecf20Sopenharmony_ci put_nfs_open_context(ctx); 11398c2ecf20Sopenharmony_ci nfs_fscache_open_file(inode, filp); 11408c2ecf20Sopenharmony_ci return 0; 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci/* 11448c2ecf20Sopenharmony_ci * This function is called whenever some part of NFS notices that 11458c2ecf20Sopenharmony_ci * the cached attributes have to be refreshed. 11468c2ecf20Sopenharmony_ci */ 11478c2ecf20Sopenharmony_ciint 11488c2ecf20Sopenharmony_ci__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) 11498c2ecf20Sopenharmony_ci{ 11508c2ecf20Sopenharmony_ci int status = -ESTALE; 11518c2ecf20Sopenharmony_ci struct nfs4_label *label = NULL; 11528c2ecf20Sopenharmony_ci struct nfs_fattr *fattr = NULL; 11538c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci dfprintk(PAGECACHE, "NFS: revalidating (%s/%Lu)\n", 11568c2ecf20Sopenharmony_ci inode->i_sb->s_id, (unsigned long long)NFS_FILEID(inode)); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci trace_nfs_revalidate_inode_enter(inode); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci if (is_bad_inode(inode)) 11618c2ecf20Sopenharmony_ci goto out; 11628c2ecf20Sopenharmony_ci if (NFS_STALE(inode)) 11638c2ecf20Sopenharmony_ci goto out; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* pNFS: Attributes aren't updated until we layoutcommit */ 11668c2ecf20Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 11678c2ecf20Sopenharmony_ci status = pnfs_sync_inode(inode, false); 11688c2ecf20Sopenharmony_ci if (status) 11698c2ecf20Sopenharmony_ci goto out; 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci status = -ENOMEM; 11738c2ecf20Sopenharmony_ci fattr = nfs_alloc_fattr(); 11748c2ecf20Sopenharmony_ci if (fattr == NULL) 11758c2ecf20Sopenharmony_ci goto out; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL); 11808c2ecf20Sopenharmony_ci if (IS_ERR(label)) { 11818c2ecf20Sopenharmony_ci status = PTR_ERR(label); 11828c2ecf20Sopenharmony_ci goto out; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, 11868c2ecf20Sopenharmony_ci label, inode); 11878c2ecf20Sopenharmony_ci if (status != 0) { 11888c2ecf20Sopenharmony_ci dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) getattr failed, error=%d\n", 11898c2ecf20Sopenharmony_ci inode->i_sb->s_id, 11908c2ecf20Sopenharmony_ci (unsigned long long)NFS_FILEID(inode), status); 11918c2ecf20Sopenharmony_ci switch (status) { 11928c2ecf20Sopenharmony_ci case -ETIMEDOUT: 11938c2ecf20Sopenharmony_ci /* A soft timeout occurred. Use cached information? */ 11948c2ecf20Sopenharmony_ci if (server->flags & NFS_MOUNT_SOFTREVAL) 11958c2ecf20Sopenharmony_ci status = 0; 11968c2ecf20Sopenharmony_ci break; 11978c2ecf20Sopenharmony_ci case -ESTALE: 11988c2ecf20Sopenharmony_ci if (!S_ISDIR(inode->i_mode)) 11998c2ecf20Sopenharmony_ci nfs_set_inode_stale(inode); 12008c2ecf20Sopenharmony_ci else 12018c2ecf20Sopenharmony_ci nfs_zap_caches(inode); 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci goto err_out; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci status = nfs_refresh_inode(inode, fattr); 12078c2ecf20Sopenharmony_ci if (status) { 12088c2ecf20Sopenharmony_ci dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) refresh failed, error=%d\n", 12098c2ecf20Sopenharmony_ci inode->i_sb->s_id, 12108c2ecf20Sopenharmony_ci (unsigned long long)NFS_FILEID(inode), status); 12118c2ecf20Sopenharmony_ci goto err_out; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (nfsi->cache_validity & NFS_INO_INVALID_ACL) 12158c2ecf20Sopenharmony_ci nfs_zap_acl_cache(inode); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci nfs_setsecurity(inode, fattr, label); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci dfprintk(PAGECACHE, "NFS: (%s/%Lu) revalidation complete\n", 12208c2ecf20Sopenharmony_ci inode->i_sb->s_id, 12218c2ecf20Sopenharmony_ci (unsigned long long)NFS_FILEID(inode)); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cierr_out: 12248c2ecf20Sopenharmony_ci nfs4_label_free(label); 12258c2ecf20Sopenharmony_ciout: 12268c2ecf20Sopenharmony_ci nfs_free_fattr(fattr); 12278c2ecf20Sopenharmony_ci trace_nfs_revalidate_inode_exit(inode, status); 12288c2ecf20Sopenharmony_ci return status; 12298c2ecf20Sopenharmony_ci} 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ciint nfs_attribute_cache_expired(struct inode *inode) 12328c2ecf20Sopenharmony_ci{ 12338c2ecf20Sopenharmony_ci if (nfs_have_delegated_attributes(inode)) 12348c2ecf20Sopenharmony_ci return 0; 12358c2ecf20Sopenharmony_ci return nfs_attribute_timeout(inode); 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci/** 12398c2ecf20Sopenharmony_ci * nfs_revalidate_inode - Revalidate the inode attributes 12408c2ecf20Sopenharmony_ci * @server: pointer to nfs_server struct 12418c2ecf20Sopenharmony_ci * @inode: pointer to inode struct 12428c2ecf20Sopenharmony_ci * 12438c2ecf20Sopenharmony_ci * Updates inode attribute information by retrieving the data from the server. 12448c2ecf20Sopenharmony_ci */ 12458c2ecf20Sopenharmony_ciint nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) 12468c2ecf20Sopenharmony_ci{ 12478c2ecf20Sopenharmony_ci if (!nfs_need_revalidate_inode(inode)) 12488c2ecf20Sopenharmony_ci return NFS_STALE(inode) ? -ESTALE : 0; 12498c2ecf20Sopenharmony_ci return __nfs_revalidate_inode(server, inode); 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_revalidate_inode); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_cistatic int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) 12548c2ecf20Sopenharmony_ci{ 12558c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 12568c2ecf20Sopenharmony_ci int ret; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci if (mapping->nrpages != 0) { 12598c2ecf20Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 12608c2ecf20Sopenharmony_ci ret = nfs_sync_mapping(mapping); 12618c2ecf20Sopenharmony_ci if (ret < 0) 12628c2ecf20Sopenharmony_ci return ret; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci ret = invalidate_inode_pages2(mapping); 12658c2ecf20Sopenharmony_ci if (ret < 0) 12668c2ecf20Sopenharmony_ci return ret; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) { 12698c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 12708c2ecf20Sopenharmony_ci memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); 12718c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); 12748c2ecf20Sopenharmony_ci nfs_fscache_wait_on_invalidate(inode); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci dfprintk(PAGECACHE, "NFS: (%s/%Lu) data cache invalidated\n", 12778c2ecf20Sopenharmony_ci inode->i_sb->s_id, 12788c2ecf20Sopenharmony_ci (unsigned long long)NFS_FILEID(inode)); 12798c2ecf20Sopenharmony_ci return 0; 12808c2ecf20Sopenharmony_ci} 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_cibool nfs_mapping_need_revalidate_inode(struct inode *inode) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci return nfs_check_cache_invalid(inode, NFS_INO_REVAL_PAGECACHE) || 12858c2ecf20Sopenharmony_ci NFS_STALE(inode); 12868c2ecf20Sopenharmony_ci} 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ciint nfs_revalidate_mapping_rcu(struct inode *inode) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 12918c2ecf20Sopenharmony_ci unsigned long *bitlock = &nfsi->flags; 12928c2ecf20Sopenharmony_ci int ret = 0; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (IS_SWAPFILE(inode)) 12958c2ecf20Sopenharmony_ci goto out; 12968c2ecf20Sopenharmony_ci if (nfs_mapping_need_revalidate_inode(inode)) { 12978c2ecf20Sopenharmony_ci ret = -ECHILD; 12988c2ecf20Sopenharmony_ci goto out; 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 13018c2ecf20Sopenharmony_ci if (test_bit(NFS_INO_INVALIDATING, bitlock) || 13028c2ecf20Sopenharmony_ci (nfsi->cache_validity & NFS_INO_INVALID_DATA)) 13038c2ecf20Sopenharmony_ci ret = -ECHILD; 13048c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 13058c2ecf20Sopenharmony_ciout: 13068c2ecf20Sopenharmony_ci return ret; 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci/** 13108c2ecf20Sopenharmony_ci * nfs_revalidate_mapping - Revalidate the pagecache 13118c2ecf20Sopenharmony_ci * @inode: pointer to host inode 13128c2ecf20Sopenharmony_ci * @mapping: pointer to mapping 13138c2ecf20Sopenharmony_ci */ 13148c2ecf20Sopenharmony_ciint nfs_revalidate_mapping(struct inode *inode, 13158c2ecf20Sopenharmony_ci struct address_space *mapping) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 13188c2ecf20Sopenharmony_ci unsigned long *bitlock = &nfsi->flags; 13198c2ecf20Sopenharmony_ci int ret = 0; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci /* swapfiles are not supposed to be shared. */ 13228c2ecf20Sopenharmony_ci if (IS_SWAPFILE(inode)) 13238c2ecf20Sopenharmony_ci goto out; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci if (nfs_mapping_need_revalidate_inode(inode)) { 13268c2ecf20Sopenharmony_ci ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); 13278c2ecf20Sopenharmony_ci if (ret < 0) 13288c2ecf20Sopenharmony_ci goto out; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci /* 13328c2ecf20Sopenharmony_ci * We must clear NFS_INO_INVALID_DATA first to ensure that 13338c2ecf20Sopenharmony_ci * invalidations that come in while we're shooting down the mappings 13348c2ecf20Sopenharmony_ci * are respected. But, that leaves a race window where one revalidator 13358c2ecf20Sopenharmony_ci * can clear the flag, and then another checks it before the mapping 13368c2ecf20Sopenharmony_ci * gets invalidated. Fix that by serializing access to this part of 13378c2ecf20Sopenharmony_ci * the function. 13388c2ecf20Sopenharmony_ci * 13398c2ecf20Sopenharmony_ci * At the same time, we need to allow other tasks to see whether we 13408c2ecf20Sopenharmony_ci * might be in the middle of invalidating the pages, so we only set 13418c2ecf20Sopenharmony_ci * the bit lock here if it looks like we're going to be doing that. 13428c2ecf20Sopenharmony_ci */ 13438c2ecf20Sopenharmony_ci for (;;) { 13448c2ecf20Sopenharmony_ci ret = wait_on_bit_action(bitlock, NFS_INO_INVALIDATING, 13458c2ecf20Sopenharmony_ci nfs_wait_bit_killable, TASK_KILLABLE); 13468c2ecf20Sopenharmony_ci if (ret) 13478c2ecf20Sopenharmony_ci goto out; 13488c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 13498c2ecf20Sopenharmony_ci if (test_bit(NFS_INO_INVALIDATING, bitlock)) { 13508c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 13518c2ecf20Sopenharmony_ci continue; 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci if (nfsi->cache_validity & NFS_INO_INVALID_DATA) 13548c2ecf20Sopenharmony_ci break; 13558c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 13568c2ecf20Sopenharmony_ci goto out; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci set_bit(NFS_INO_INVALIDATING, bitlock); 13608c2ecf20Sopenharmony_ci smp_wmb(); 13618c2ecf20Sopenharmony_ci nfsi->cache_validity &= ~(NFS_INO_INVALID_DATA| 13628c2ecf20Sopenharmony_ci NFS_INO_DATA_INVAL_DEFER); 13638c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 13648c2ecf20Sopenharmony_ci trace_nfs_invalidate_mapping_enter(inode); 13658c2ecf20Sopenharmony_ci ret = nfs_invalidate_mapping(inode, mapping); 13668c2ecf20Sopenharmony_ci trace_nfs_invalidate_mapping_exit(inode, ret); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci clear_bit_unlock(NFS_INO_INVALIDATING, bitlock); 13698c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 13708c2ecf20Sopenharmony_ci wake_up_bit(bitlock, NFS_INO_INVALIDATING); 13718c2ecf20Sopenharmony_ciout: 13728c2ecf20Sopenharmony_ci return ret; 13738c2ecf20Sopenharmony_ci} 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_cistatic bool nfs_file_has_writers(struct nfs_inode *nfsi) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci struct inode *inode = &nfsi->vfs_inode; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (!S_ISREG(inode->i_mode)) 13808c2ecf20Sopenharmony_ci return false; 13818c2ecf20Sopenharmony_ci if (list_empty(&nfsi->open_files)) 13828c2ecf20Sopenharmony_ci return false; 13838c2ecf20Sopenharmony_ci return inode_is_open_for_write(inode); 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic bool nfs_file_has_buffered_writers(struct nfs_inode *nfsi) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci return nfs_file_has_writers(nfsi) && nfs_file_io_is_buffered(nfsi); 13898c2ecf20Sopenharmony_ci} 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_cistatic void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr) 13928c2ecf20Sopenharmony_ci{ 13938c2ecf20Sopenharmony_ci struct timespec64 ts; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE) 13968c2ecf20Sopenharmony_ci && (fattr->valid & NFS_ATTR_FATTR_CHANGE) 13978c2ecf20Sopenharmony_ci && inode_eq_iversion_raw(inode, fattr->pre_change_attr)) { 13988c2ecf20Sopenharmony_ci inode_set_iversion_raw(inode, fattr->change_attr); 13998c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 14008c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA); 14018c2ecf20Sopenharmony_ci else if (nfs_server_capable(inode, NFS_CAP_XATTR)) 14028c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_XATTR); 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci /* If we have atomic WCC data, we may update some attributes */ 14058c2ecf20Sopenharmony_ci ts = inode->i_ctime; 14068c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME) 14078c2ecf20Sopenharmony_ci && (fattr->valid & NFS_ATTR_FATTR_CTIME) 14088c2ecf20Sopenharmony_ci && timespec64_equal(&ts, &fattr->pre_ctime)) { 14098c2ecf20Sopenharmony_ci inode->i_ctime = fattr->ctime; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci ts = inode->i_mtime; 14138c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME) 14148c2ecf20Sopenharmony_ci && (fattr->valid & NFS_ATTR_FATTR_MTIME) 14158c2ecf20Sopenharmony_ci && timespec64_equal(&ts, &fattr->pre_mtime)) { 14168c2ecf20Sopenharmony_ci inode->i_mtime = fattr->mtime; 14178c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 14188c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, NFS_INO_INVALID_DATA); 14198c2ecf20Sopenharmony_ci } 14208c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE) 14218c2ecf20Sopenharmony_ci && (fattr->valid & NFS_ATTR_FATTR_SIZE) 14228c2ecf20Sopenharmony_ci && i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size) 14238c2ecf20Sopenharmony_ci && !nfs_have_writebacks(inode)) { 14248c2ecf20Sopenharmony_ci i_size_write(inode, nfs_size_to_loff_t(fattr->size)); 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci} 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci/** 14298c2ecf20Sopenharmony_ci * nfs_check_inode_attributes - verify consistency of the inode attribute cache 14308c2ecf20Sopenharmony_ci * @inode: pointer to inode 14318c2ecf20Sopenharmony_ci * @fattr: updated attributes 14328c2ecf20Sopenharmony_ci * 14338c2ecf20Sopenharmony_ci * Verifies the attribute cache. If we have just changed the attributes, 14348c2ecf20Sopenharmony_ci * so that fattr carries weak cache consistency data, then it may 14358c2ecf20Sopenharmony_ci * also update the ctime/mtime/change_attribute. 14368c2ecf20Sopenharmony_ci */ 14378c2ecf20Sopenharmony_cistatic int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fattr) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 14408c2ecf20Sopenharmony_ci loff_t cur_size, new_isize; 14418c2ecf20Sopenharmony_ci unsigned long invalid = 0; 14428c2ecf20Sopenharmony_ci struct timespec64 ts; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) 14458c2ecf20Sopenharmony_ci return 0; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci if (!(fattr->valid & NFS_ATTR_FATTR_FILEID)) { 14488c2ecf20Sopenharmony_ci /* Only a mounted-on-fileid? Just exit */ 14498c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) 14508c2ecf20Sopenharmony_ci return 0; 14518c2ecf20Sopenharmony_ci /* Has the inode gone and changed behind our back? */ 14528c2ecf20Sopenharmony_ci } else if (nfsi->fileid != fattr->fileid) { 14538c2ecf20Sopenharmony_ci /* Is this perhaps the mounted-on fileid? */ 14548c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) && 14558c2ecf20Sopenharmony_ci nfsi->fileid == fattr->mounted_on_fileid) 14568c2ecf20Sopenharmony_ci return 0; 14578c2ecf20Sopenharmony_ci return -ESTALE; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && inode_wrong_type(inode, fattr->mode)) 14608c2ecf20Sopenharmony_ci return -ESTALE; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci if (!nfs_file_has_buffered_writers(nfsi)) { 14648c2ecf20Sopenharmony_ci /* Verify a few of the more important attributes */ 14658c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && !inode_eq_iversion_raw(inode, fattr->change_attr)) 14668c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_CHANGE 14678c2ecf20Sopenharmony_ci | NFS_INO_REVAL_PAGECACHE; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci ts = inode->i_mtime; 14708c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec64_equal(&ts, &fattr->mtime)) 14718c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_MTIME; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci ts = inode->i_ctime; 14748c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_CTIME) && !timespec64_equal(&ts, &fattr->ctime)) 14758c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_CTIME; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_SIZE) { 14788c2ecf20Sopenharmony_ci cur_size = i_size_read(inode); 14798c2ecf20Sopenharmony_ci new_isize = nfs_size_to_loff_t(fattr->size); 14808c2ecf20Sopenharmony_ci if (cur_size != new_isize) 14818c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_SIZE 14828c2ecf20Sopenharmony_ci | NFS_INO_REVAL_PAGECACHE; 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci /* Have any file permissions changed? */ 14878c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) 14888c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_ACCESS 14898c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACL 14908c2ecf20Sopenharmony_ci | NFS_INO_INVALID_OTHER; 14918c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && !uid_eq(inode->i_uid, fattr->uid)) 14928c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_ACCESS 14938c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACL 14948c2ecf20Sopenharmony_ci | NFS_INO_INVALID_OTHER; 14958c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && !gid_eq(inode->i_gid, fattr->gid)) 14968c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_ACCESS 14978c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACL 14988c2ecf20Sopenharmony_ci | NFS_INO_INVALID_OTHER; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci /* Has the link count changed? */ 15018c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_NLINK) && inode->i_nlink != fattr->nlink) 15028c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_OTHER; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci ts = inode->i_atime; 15058c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_ATIME) && !timespec64_equal(&ts, &fattr->atime)) 15068c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_ATIME; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci if (invalid != 0) 15098c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, invalid); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci nfsi->read_cache_jiffies = fattr->time_start; 15128c2ecf20Sopenharmony_ci return 0; 15138c2ecf20Sopenharmony_ci} 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_cistatic atomic_long_t nfs_attr_generation_counter; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_cistatic unsigned long nfs_read_attr_generation_counter(void) 15188c2ecf20Sopenharmony_ci{ 15198c2ecf20Sopenharmony_ci return atomic_long_read(&nfs_attr_generation_counter); 15208c2ecf20Sopenharmony_ci} 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ciunsigned long nfs_inc_attr_generation_counter(void) 15238c2ecf20Sopenharmony_ci{ 15248c2ecf20Sopenharmony_ci return atomic_long_inc_return(&nfs_attr_generation_counter); 15258c2ecf20Sopenharmony_ci} 15268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_inc_attr_generation_counter); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_civoid nfs_fattr_init(struct nfs_fattr *fattr) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci fattr->valid = 0; 15318c2ecf20Sopenharmony_ci fattr->time_start = jiffies; 15328c2ecf20Sopenharmony_ci fattr->gencount = nfs_inc_attr_generation_counter(); 15338c2ecf20Sopenharmony_ci fattr->owner_name = NULL; 15348c2ecf20Sopenharmony_ci fattr->group_name = NULL; 15358c2ecf20Sopenharmony_ci} 15368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_fattr_init); 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci/** 15398c2ecf20Sopenharmony_ci * nfs_fattr_set_barrier 15408c2ecf20Sopenharmony_ci * @fattr: attributes 15418c2ecf20Sopenharmony_ci * 15428c2ecf20Sopenharmony_ci * Used to set a barrier after an attribute was updated. This 15438c2ecf20Sopenharmony_ci * barrier ensures that older attributes from RPC calls that may 15448c2ecf20Sopenharmony_ci * have raced with our update cannot clobber these new values. 15458c2ecf20Sopenharmony_ci * Note that you are still responsible for ensuring that other 15468c2ecf20Sopenharmony_ci * operations which change the attribute on the server do not 15478c2ecf20Sopenharmony_ci * collide. 15488c2ecf20Sopenharmony_ci */ 15498c2ecf20Sopenharmony_civoid nfs_fattr_set_barrier(struct nfs_fattr *fattr) 15508c2ecf20Sopenharmony_ci{ 15518c2ecf20Sopenharmony_ci fattr->gencount = nfs_inc_attr_generation_counter(); 15528c2ecf20Sopenharmony_ci} 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_cistruct nfs_fattr *nfs_alloc_fattr(void) 15558c2ecf20Sopenharmony_ci{ 15568c2ecf20Sopenharmony_ci struct nfs_fattr *fattr; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci fattr = kmalloc(sizeof(*fattr), GFP_NOFS); 15598c2ecf20Sopenharmony_ci if (fattr != NULL) 15608c2ecf20Sopenharmony_ci nfs_fattr_init(fattr); 15618c2ecf20Sopenharmony_ci return fattr; 15628c2ecf20Sopenharmony_ci} 15638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_alloc_fattr); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_cistruct nfs_fh *nfs_alloc_fhandle(void) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci struct nfs_fh *fh; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci fh = kmalloc(sizeof(struct nfs_fh), GFP_NOFS); 15708c2ecf20Sopenharmony_ci if (fh != NULL) 15718c2ecf20Sopenharmony_ci fh->size = 0; 15728c2ecf20Sopenharmony_ci return fh; 15738c2ecf20Sopenharmony_ci} 15748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_alloc_fhandle); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci#ifdef NFS_DEBUG 15778c2ecf20Sopenharmony_ci/* 15788c2ecf20Sopenharmony_ci * _nfs_display_fhandle_hash - calculate the crc32 hash for the filehandle 15798c2ecf20Sopenharmony_ci * in the same way that wireshark does 15808c2ecf20Sopenharmony_ci * 15818c2ecf20Sopenharmony_ci * @fh: file handle 15828c2ecf20Sopenharmony_ci * 15838c2ecf20Sopenharmony_ci * For debugging only. 15848c2ecf20Sopenharmony_ci */ 15858c2ecf20Sopenharmony_ciu32 _nfs_display_fhandle_hash(const struct nfs_fh *fh) 15868c2ecf20Sopenharmony_ci{ 15878c2ecf20Sopenharmony_ci /* wireshark uses 32-bit AUTODIN crc and does a bitwise 15888c2ecf20Sopenharmony_ci * not on the result */ 15898c2ecf20Sopenharmony_ci return nfs_fhandle_hash(fh); 15908c2ecf20Sopenharmony_ci} 15918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(_nfs_display_fhandle_hash); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci/* 15948c2ecf20Sopenharmony_ci * _nfs_display_fhandle - display an NFS file handle on the console 15958c2ecf20Sopenharmony_ci * 15968c2ecf20Sopenharmony_ci * @fh: file handle to display 15978c2ecf20Sopenharmony_ci * @caption: display caption 15988c2ecf20Sopenharmony_ci * 15998c2ecf20Sopenharmony_ci * For debugging only. 16008c2ecf20Sopenharmony_ci */ 16018c2ecf20Sopenharmony_civoid _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption) 16028c2ecf20Sopenharmony_ci{ 16038c2ecf20Sopenharmony_ci unsigned short i; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci if (fh == NULL || fh->size == 0) { 16068c2ecf20Sopenharmony_ci printk(KERN_DEFAULT "%s at %p is empty\n", caption, fh); 16078c2ecf20Sopenharmony_ci return; 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci printk(KERN_DEFAULT "%s at %p is %u bytes, crc: 0x%08x:\n", 16118c2ecf20Sopenharmony_ci caption, fh, fh->size, _nfs_display_fhandle_hash(fh)); 16128c2ecf20Sopenharmony_ci for (i = 0; i < fh->size; i += 16) { 16138c2ecf20Sopenharmony_ci __be32 *pos = (__be32 *)&fh->data[i]; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci switch ((fh->size - i - 1) >> 2) { 16168c2ecf20Sopenharmony_ci case 0: 16178c2ecf20Sopenharmony_ci printk(KERN_DEFAULT " %08x\n", 16188c2ecf20Sopenharmony_ci be32_to_cpup(pos)); 16198c2ecf20Sopenharmony_ci break; 16208c2ecf20Sopenharmony_ci case 1: 16218c2ecf20Sopenharmony_ci printk(KERN_DEFAULT " %08x %08x\n", 16228c2ecf20Sopenharmony_ci be32_to_cpup(pos), be32_to_cpup(pos + 1)); 16238c2ecf20Sopenharmony_ci break; 16248c2ecf20Sopenharmony_ci case 2: 16258c2ecf20Sopenharmony_ci printk(KERN_DEFAULT " %08x %08x %08x\n", 16268c2ecf20Sopenharmony_ci be32_to_cpup(pos), be32_to_cpup(pos + 1), 16278c2ecf20Sopenharmony_ci be32_to_cpup(pos + 2)); 16288c2ecf20Sopenharmony_ci break; 16298c2ecf20Sopenharmony_ci default: 16308c2ecf20Sopenharmony_ci printk(KERN_DEFAULT " %08x %08x %08x %08x\n", 16318c2ecf20Sopenharmony_ci be32_to_cpup(pos), be32_to_cpup(pos + 1), 16328c2ecf20Sopenharmony_ci be32_to_cpup(pos + 2), be32_to_cpup(pos + 3)); 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(_nfs_display_fhandle); 16378c2ecf20Sopenharmony_ci#endif 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci/** 16408c2ecf20Sopenharmony_ci * nfs_inode_attrs_need_update - check if the inode attributes need updating 16418c2ecf20Sopenharmony_ci * @inode: pointer to inode 16428c2ecf20Sopenharmony_ci * @fattr: attributes 16438c2ecf20Sopenharmony_ci * 16448c2ecf20Sopenharmony_ci * Attempt to divine whether or not an RPC call reply carrying stale 16458c2ecf20Sopenharmony_ci * attributes got scheduled after another call carrying updated ones. 16468c2ecf20Sopenharmony_ci * 16478c2ecf20Sopenharmony_ci * To do so, the function first assumes that a more recent ctime means 16488c2ecf20Sopenharmony_ci * that the attributes in fattr are newer, however it also attempt to 16498c2ecf20Sopenharmony_ci * catch the case where ctime either didn't change, or went backwards 16508c2ecf20Sopenharmony_ci * (if someone reset the clock on the server) by looking at whether 16518c2ecf20Sopenharmony_ci * or not this RPC call was started after the inode was last updated. 16528c2ecf20Sopenharmony_ci * Note also the check for wraparound of 'attr_gencount' 16538c2ecf20Sopenharmony_ci * 16548c2ecf20Sopenharmony_ci * The function returns 'true' if it thinks the attributes in 'fattr' are 16558c2ecf20Sopenharmony_ci * more recent than the ones cached in the inode. 16568c2ecf20Sopenharmony_ci * 16578c2ecf20Sopenharmony_ci */ 16588c2ecf20Sopenharmony_cistatic int nfs_inode_attrs_need_update(const struct inode *inode, const struct nfs_fattr *fattr) 16598c2ecf20Sopenharmony_ci{ 16608c2ecf20Sopenharmony_ci unsigned long attr_gencount = NFS_I(inode)->attr_gencount; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci return (long)(fattr->gencount - attr_gencount) > 0 || 16638c2ecf20Sopenharmony_ci (long)(attr_gencount - nfs_read_attr_generation_counter()) > 0; 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_cistatic int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci int ret; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci trace_nfs_refresh_inode_enter(inode); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci if (nfs_inode_attrs_need_update(inode, fattr)) 16738c2ecf20Sopenharmony_ci ret = nfs_update_inode(inode, fattr); 16748c2ecf20Sopenharmony_ci else 16758c2ecf20Sopenharmony_ci ret = nfs_check_inode_attributes(inode, fattr); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci trace_nfs_refresh_inode_exit(inode, ret); 16788c2ecf20Sopenharmony_ci return ret; 16798c2ecf20Sopenharmony_ci} 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci/** 16828c2ecf20Sopenharmony_ci * nfs_refresh_inode - try to update the inode attribute cache 16838c2ecf20Sopenharmony_ci * @inode: pointer to inode 16848c2ecf20Sopenharmony_ci * @fattr: updated attributes 16858c2ecf20Sopenharmony_ci * 16868c2ecf20Sopenharmony_ci * Check that an RPC call that returned attributes has not overlapped with 16878c2ecf20Sopenharmony_ci * other recent updates of the inode metadata, then decide whether it is 16888c2ecf20Sopenharmony_ci * safe to do a full update of the inode attributes, or whether just to 16898c2ecf20Sopenharmony_ci * call nfs_check_inode_attributes. 16908c2ecf20Sopenharmony_ci */ 16918c2ecf20Sopenharmony_ciint nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) 16928c2ecf20Sopenharmony_ci{ 16938c2ecf20Sopenharmony_ci int status; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR) == 0) 16968c2ecf20Sopenharmony_ci return 0; 16978c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 16988c2ecf20Sopenharmony_ci status = nfs_refresh_inode_locked(inode, fattr); 16998c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci return status; 17028c2ecf20Sopenharmony_ci} 17038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_refresh_inode); 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_cistatic int nfs_post_op_update_inode_locked(struct inode *inode, 17068c2ecf20Sopenharmony_ci struct nfs_fattr *fattr, unsigned int invalid) 17078c2ecf20Sopenharmony_ci{ 17088c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 17098c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_DATA; 17108c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, invalid); 17118c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR) == 0) 17128c2ecf20Sopenharmony_ci return 0; 17138c2ecf20Sopenharmony_ci return nfs_refresh_inode_locked(inode, fattr); 17148c2ecf20Sopenharmony_ci} 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci/** 17178c2ecf20Sopenharmony_ci * nfs_post_op_update_inode - try to update the inode attribute cache 17188c2ecf20Sopenharmony_ci * @inode: pointer to inode 17198c2ecf20Sopenharmony_ci * @fattr: updated attributes 17208c2ecf20Sopenharmony_ci * 17218c2ecf20Sopenharmony_ci * After an operation that has changed the inode metadata, mark the 17228c2ecf20Sopenharmony_ci * attribute cache as being invalid, then try to update it. 17238c2ecf20Sopenharmony_ci * 17248c2ecf20Sopenharmony_ci * NB: if the server didn't return any post op attributes, this 17258c2ecf20Sopenharmony_ci * function will force the retrieval of attributes before the next 17268c2ecf20Sopenharmony_ci * NFS request. Thus it should be used only for operations that 17278c2ecf20Sopenharmony_ci * are expected to change one or more attributes, to avoid 17288c2ecf20Sopenharmony_ci * unnecessary NFS requests and trips through nfs_update_inode(). 17298c2ecf20Sopenharmony_ci */ 17308c2ecf20Sopenharmony_ciint nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci int status; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 17358c2ecf20Sopenharmony_ci nfs_fattr_set_barrier(fattr); 17368c2ecf20Sopenharmony_ci status = nfs_post_op_update_inode_locked(inode, fattr, 17378c2ecf20Sopenharmony_ci NFS_INO_INVALID_CHANGE 17388c2ecf20Sopenharmony_ci | NFS_INO_INVALID_CTIME 17398c2ecf20Sopenharmony_ci | NFS_INO_REVAL_FORCED); 17408c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci return status; 17438c2ecf20Sopenharmony_ci} 17448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_post_op_update_inode); 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci/** 17478c2ecf20Sopenharmony_ci * nfs_post_op_update_inode_force_wcc_locked - update the inode attribute cache 17488c2ecf20Sopenharmony_ci * @inode: pointer to inode 17498c2ecf20Sopenharmony_ci * @fattr: updated attributes 17508c2ecf20Sopenharmony_ci * 17518c2ecf20Sopenharmony_ci * After an operation that has changed the inode metadata, mark the 17528c2ecf20Sopenharmony_ci * attribute cache as being invalid, then try to update it. Fake up 17538c2ecf20Sopenharmony_ci * weak cache consistency data, if none exist. 17548c2ecf20Sopenharmony_ci * 17558c2ecf20Sopenharmony_ci * This function is mainly designed to be used by the ->write_done() functions. 17568c2ecf20Sopenharmony_ci */ 17578c2ecf20Sopenharmony_ciint nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr) 17588c2ecf20Sopenharmony_ci{ 17598c2ecf20Sopenharmony_ci int status; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci /* Don't do a WCC update if these attributes are already stale */ 17628c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR) == 0 || 17638c2ecf20Sopenharmony_ci !nfs_inode_attrs_need_update(inode, fattr)) { 17648c2ecf20Sopenharmony_ci fattr->valid &= ~(NFS_ATTR_FATTR_PRECHANGE 17658c2ecf20Sopenharmony_ci | NFS_ATTR_FATTR_PRESIZE 17668c2ecf20Sopenharmony_ci | NFS_ATTR_FATTR_PREMTIME 17678c2ecf20Sopenharmony_ci | NFS_ATTR_FATTR_PRECTIME); 17688c2ecf20Sopenharmony_ci goto out_noforce; 17698c2ecf20Sopenharmony_ci } 17708c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 && 17718c2ecf20Sopenharmony_ci (fattr->valid & NFS_ATTR_FATTR_PRECHANGE) == 0) { 17728c2ecf20Sopenharmony_ci fattr->pre_change_attr = inode_peek_iversion_raw(inode); 17738c2ecf20Sopenharmony_ci fattr->valid |= NFS_ATTR_FATTR_PRECHANGE; 17748c2ecf20Sopenharmony_ci } 17758c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_CTIME) != 0 && 17768c2ecf20Sopenharmony_ci (fattr->valid & NFS_ATTR_FATTR_PRECTIME) == 0) { 17778c2ecf20Sopenharmony_ci fattr->pre_ctime = inode->i_ctime; 17788c2ecf20Sopenharmony_ci fattr->valid |= NFS_ATTR_FATTR_PRECTIME; 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_MTIME) != 0 && 17818c2ecf20Sopenharmony_ci (fattr->valid & NFS_ATTR_FATTR_PREMTIME) == 0) { 17828c2ecf20Sopenharmony_ci fattr->pre_mtime = inode->i_mtime; 17838c2ecf20Sopenharmony_ci fattr->valid |= NFS_ATTR_FATTR_PREMTIME; 17848c2ecf20Sopenharmony_ci } 17858c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_SIZE) != 0 && 17868c2ecf20Sopenharmony_ci (fattr->valid & NFS_ATTR_FATTR_PRESIZE) == 0) { 17878c2ecf20Sopenharmony_ci fattr->pre_size = i_size_read(inode); 17888c2ecf20Sopenharmony_ci fattr->valid |= NFS_ATTR_FATTR_PRESIZE; 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ciout_noforce: 17918c2ecf20Sopenharmony_ci status = nfs_post_op_update_inode_locked(inode, fattr, 17928c2ecf20Sopenharmony_ci NFS_INO_INVALID_CHANGE 17938c2ecf20Sopenharmony_ci | NFS_INO_INVALID_CTIME 17948c2ecf20Sopenharmony_ci | NFS_INO_INVALID_MTIME 17958c2ecf20Sopenharmony_ci | NFS_INO_INVALID_BLOCKS); 17968c2ecf20Sopenharmony_ci return status; 17978c2ecf20Sopenharmony_ci} 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci/** 18008c2ecf20Sopenharmony_ci * nfs_post_op_update_inode_force_wcc - try to update the inode attribute cache 18018c2ecf20Sopenharmony_ci * @inode: pointer to inode 18028c2ecf20Sopenharmony_ci * @fattr: updated attributes 18038c2ecf20Sopenharmony_ci * 18048c2ecf20Sopenharmony_ci * After an operation that has changed the inode metadata, mark the 18058c2ecf20Sopenharmony_ci * attribute cache as being invalid, then try to update it. Fake up 18068c2ecf20Sopenharmony_ci * weak cache consistency data, if none exist. 18078c2ecf20Sopenharmony_ci * 18088c2ecf20Sopenharmony_ci * This function is mainly designed to be used by the ->write_done() functions. 18098c2ecf20Sopenharmony_ci */ 18108c2ecf20Sopenharmony_ciint nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr) 18118c2ecf20Sopenharmony_ci{ 18128c2ecf20Sopenharmony_ci int status; 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci spin_lock(&inode->i_lock); 18158c2ecf20Sopenharmony_ci nfs_fattr_set_barrier(fattr); 18168c2ecf20Sopenharmony_ci status = nfs_post_op_update_inode_force_wcc_locked(inode, fattr); 18178c2ecf20Sopenharmony_ci spin_unlock(&inode->i_lock); 18188c2ecf20Sopenharmony_ci return status; 18198c2ecf20Sopenharmony_ci} 18208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_post_op_update_inode_force_wcc); 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci/* 18248c2ecf20Sopenharmony_ci * Many nfs protocol calls return the new file attributes after 18258c2ecf20Sopenharmony_ci * an operation. Here we update the inode to reflect the state 18268c2ecf20Sopenharmony_ci * of the server's inode. 18278c2ecf20Sopenharmony_ci * 18288c2ecf20Sopenharmony_ci * This is a bit tricky because we have to make sure all dirty pages 18298c2ecf20Sopenharmony_ci * have been sent off to the server before calling invalidate_inode_pages. 18308c2ecf20Sopenharmony_ci * To make sure no other process adds more write requests while we try 18318c2ecf20Sopenharmony_ci * our best to flush them, we make them sleep during the attribute refresh. 18328c2ecf20Sopenharmony_ci * 18338c2ecf20Sopenharmony_ci * A very similar scenario holds for the dir cache. 18348c2ecf20Sopenharmony_ci */ 18358c2ecf20Sopenharmony_cistatic int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) 18368c2ecf20Sopenharmony_ci{ 18378c2ecf20Sopenharmony_ci struct nfs_server *server; 18388c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = NFS_I(inode); 18398c2ecf20Sopenharmony_ci loff_t cur_isize, new_isize; 18408c2ecf20Sopenharmony_ci unsigned long invalid = 0; 18418c2ecf20Sopenharmony_ci unsigned long now = jiffies; 18428c2ecf20Sopenharmony_ci unsigned long save_cache_validity; 18438c2ecf20Sopenharmony_ci bool have_writers = nfs_file_has_buffered_writers(nfsi); 18448c2ecf20Sopenharmony_ci bool cache_revalidated = true; 18458c2ecf20Sopenharmony_ci bool attr_changed = false; 18468c2ecf20Sopenharmony_ci bool have_delegation; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n", 18498c2ecf20Sopenharmony_ci __func__, inode->i_sb->s_id, inode->i_ino, 18508c2ecf20Sopenharmony_ci nfs_display_fhandle_hash(NFS_FH(inode)), 18518c2ecf20Sopenharmony_ci atomic_read(&inode->i_count), fattr->valid); 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci if (!(fattr->valid & NFS_ATTR_FATTR_FILEID)) { 18548c2ecf20Sopenharmony_ci /* Only a mounted-on-fileid? Just exit */ 18558c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) 18568c2ecf20Sopenharmony_ci return 0; 18578c2ecf20Sopenharmony_ci /* Has the inode gone and changed behind our back? */ 18588c2ecf20Sopenharmony_ci } else if (nfsi->fileid != fattr->fileid) { 18598c2ecf20Sopenharmony_ci /* Is this perhaps the mounted-on fileid? */ 18608c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) && 18618c2ecf20Sopenharmony_ci nfsi->fileid == fattr->mounted_on_fileid) 18628c2ecf20Sopenharmony_ci return 0; 18638c2ecf20Sopenharmony_ci printk(KERN_ERR "NFS: server %s error: fileid changed\n" 18648c2ecf20Sopenharmony_ci "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n", 18658c2ecf20Sopenharmony_ci NFS_SERVER(inode)->nfs_client->cl_hostname, 18668c2ecf20Sopenharmony_ci inode->i_sb->s_id, (long long)nfsi->fileid, 18678c2ecf20Sopenharmony_ci (long long)fattr->fileid); 18688c2ecf20Sopenharmony_ci goto out_err; 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci /* 18728c2ecf20Sopenharmony_ci * Make sure the inode's type hasn't changed. 18738c2ecf20Sopenharmony_ci */ 18748c2ecf20Sopenharmony_ci if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && inode_wrong_type(inode, fattr->mode)) { 18758c2ecf20Sopenharmony_ci /* 18768c2ecf20Sopenharmony_ci * Big trouble! The inode has become a different object. 18778c2ecf20Sopenharmony_ci */ 18788c2ecf20Sopenharmony_ci printk(KERN_DEBUG "NFS: %s: inode %lu mode changed, %07o to %07o\n", 18798c2ecf20Sopenharmony_ci __func__, inode->i_ino, inode->i_mode, fattr->mode); 18808c2ecf20Sopenharmony_ci goto out_err; 18818c2ecf20Sopenharmony_ci } 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci server = NFS_SERVER(inode); 18848c2ecf20Sopenharmony_ci /* Update the fsid? */ 18858c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) && 18868c2ecf20Sopenharmony_ci !nfs_fsid_equal(&server->fsid, &fattr->fsid) && 18878c2ecf20Sopenharmony_ci !IS_AUTOMOUNT(inode)) 18888c2ecf20Sopenharmony_ci server->fsid = fattr->fsid; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci /* Save the delegation state before clearing cache_validity */ 18918c2ecf20Sopenharmony_ci have_delegation = nfs_have_delegated_attributes(inode); 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci /* 18948c2ecf20Sopenharmony_ci * Update the read time so we don't revalidate too often. 18958c2ecf20Sopenharmony_ci */ 18968c2ecf20Sopenharmony_ci nfsi->read_cache_jiffies = fattr->time_start; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci save_cache_validity = nfsi->cache_validity; 18998c2ecf20Sopenharmony_ci nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR 19008c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ATIME 19018c2ecf20Sopenharmony_ci | NFS_INO_REVAL_FORCED 19028c2ecf20Sopenharmony_ci | NFS_INO_REVAL_PAGECACHE 19038c2ecf20Sopenharmony_ci | NFS_INO_INVALID_BLOCKS); 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci /* Do atomic weak cache consistency updates */ 19068c2ecf20Sopenharmony_ci nfs_wcc_update_inode(inode, fattr); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci if (pnfs_layoutcommit_outstanding(inode)) { 19098c2ecf20Sopenharmony_ci nfsi->cache_validity |= 19108c2ecf20Sopenharmony_ci save_cache_validity & 19118c2ecf20Sopenharmony_ci (NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME | 19128c2ecf20Sopenharmony_ci NFS_INO_INVALID_MTIME | NFS_INO_INVALID_SIZE | 19138c2ecf20Sopenharmony_ci NFS_INO_REVAL_FORCED); 19148c2ecf20Sopenharmony_ci cache_revalidated = false; 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci /* More cache consistency checks */ 19188c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CHANGE) { 19198c2ecf20Sopenharmony_ci if (!inode_eq_iversion_raw(inode, fattr->change_attr)) { 19208c2ecf20Sopenharmony_ci /* Could it be a race with writeback? */ 19218c2ecf20Sopenharmony_ci if (!(have_writers || have_delegation)) { 19228c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_DATA 19238c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACCESS 19248c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACL 19258c2ecf20Sopenharmony_ci | NFS_INO_INVALID_XATTR; 19268c2ecf20Sopenharmony_ci /* Force revalidate of all attributes */ 19278c2ecf20Sopenharmony_ci save_cache_validity |= NFS_INO_INVALID_CTIME 19288c2ecf20Sopenharmony_ci | NFS_INO_INVALID_MTIME 19298c2ecf20Sopenharmony_ci | NFS_INO_INVALID_SIZE 19308c2ecf20Sopenharmony_ci | NFS_INO_INVALID_OTHER; 19318c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 19328c2ecf20Sopenharmony_ci nfs_force_lookup_revalidate(inode); 19338c2ecf20Sopenharmony_ci dprintk("NFS: change_attr change on server for file %s/%ld\n", 19348c2ecf20Sopenharmony_ci inode->i_sb->s_id, 19358c2ecf20Sopenharmony_ci inode->i_ino); 19368c2ecf20Sopenharmony_ci } else if (!have_delegation) 19378c2ecf20Sopenharmony_ci nfsi->cache_validity |= NFS_INO_DATA_INVAL_DEFER; 19388c2ecf20Sopenharmony_ci inode_set_iversion_raw(inode, fattr->change_attr); 19398c2ecf20Sopenharmony_ci attr_changed = true; 19408c2ecf20Sopenharmony_ci } 19418c2ecf20Sopenharmony_ci } else { 19428c2ecf20Sopenharmony_ci nfsi->cache_validity |= save_cache_validity & 19438c2ecf20Sopenharmony_ci (NFS_INO_INVALID_CHANGE 19448c2ecf20Sopenharmony_ci | NFS_INO_REVAL_PAGECACHE 19458c2ecf20Sopenharmony_ci | NFS_INO_REVAL_FORCED); 19468c2ecf20Sopenharmony_ci cache_revalidated = false; 19478c2ecf20Sopenharmony_ci } 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MTIME) { 19508c2ecf20Sopenharmony_ci inode->i_mtime = fattr->mtime; 19518c2ecf20Sopenharmony_ci } else if (server->caps & NFS_CAP_MTIME) { 19528c2ecf20Sopenharmony_ci nfsi->cache_validity |= save_cache_validity & 19538c2ecf20Sopenharmony_ci (NFS_INO_INVALID_MTIME 19548c2ecf20Sopenharmony_ci | NFS_INO_REVAL_FORCED); 19558c2ecf20Sopenharmony_ci cache_revalidated = false; 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_CTIME) { 19598c2ecf20Sopenharmony_ci inode->i_ctime = fattr->ctime; 19608c2ecf20Sopenharmony_ci } else if (server->caps & NFS_CAP_CTIME) { 19618c2ecf20Sopenharmony_ci nfsi->cache_validity |= save_cache_validity & 19628c2ecf20Sopenharmony_ci (NFS_INO_INVALID_CTIME 19638c2ecf20Sopenharmony_ci | NFS_INO_REVAL_FORCED); 19648c2ecf20Sopenharmony_ci cache_revalidated = false; 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci /* Check if our cached file size is stale */ 19688c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_SIZE) { 19698c2ecf20Sopenharmony_ci new_isize = nfs_size_to_loff_t(fattr->size); 19708c2ecf20Sopenharmony_ci cur_isize = i_size_read(inode); 19718c2ecf20Sopenharmony_ci if (new_isize != cur_isize && !have_delegation) { 19728c2ecf20Sopenharmony_ci /* Do we perhaps have any outstanding writes, or has 19738c2ecf20Sopenharmony_ci * the file grown beyond our last write? */ 19748c2ecf20Sopenharmony_ci if (!nfs_have_writebacks(inode) || new_isize > cur_isize) { 19758c2ecf20Sopenharmony_ci i_size_write(inode, new_isize); 19768c2ecf20Sopenharmony_ci if (!have_writers) 19778c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_DATA; 19788c2ecf20Sopenharmony_ci attr_changed = true; 19798c2ecf20Sopenharmony_ci } 19808c2ecf20Sopenharmony_ci dprintk("NFS: isize change on server for file %s/%ld " 19818c2ecf20Sopenharmony_ci "(%Ld to %Ld)\n", 19828c2ecf20Sopenharmony_ci inode->i_sb->s_id, 19838c2ecf20Sopenharmony_ci inode->i_ino, 19848c2ecf20Sopenharmony_ci (long long)cur_isize, 19858c2ecf20Sopenharmony_ci (long long)new_isize); 19868c2ecf20Sopenharmony_ci } 19878c2ecf20Sopenharmony_ci } else { 19888c2ecf20Sopenharmony_ci nfsi->cache_validity |= save_cache_validity & 19898c2ecf20Sopenharmony_ci (NFS_INO_INVALID_SIZE 19908c2ecf20Sopenharmony_ci | NFS_INO_REVAL_PAGECACHE 19918c2ecf20Sopenharmony_ci | NFS_INO_REVAL_FORCED); 19928c2ecf20Sopenharmony_ci cache_revalidated = false; 19938c2ecf20Sopenharmony_ci } 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_ATIME) 19978c2ecf20Sopenharmony_ci inode->i_atime = fattr->atime; 19988c2ecf20Sopenharmony_ci else if (server->caps & NFS_CAP_ATIME) { 19998c2ecf20Sopenharmony_ci nfsi->cache_validity |= save_cache_validity & 20008c2ecf20Sopenharmony_ci (NFS_INO_INVALID_ATIME 20018c2ecf20Sopenharmony_ci | NFS_INO_REVAL_FORCED); 20028c2ecf20Sopenharmony_ci cache_revalidated = false; 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_MODE) { 20068c2ecf20Sopenharmony_ci if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { 20078c2ecf20Sopenharmony_ci umode_t newmode = inode->i_mode & S_IFMT; 20088c2ecf20Sopenharmony_ci newmode |= fattr->mode & S_IALLUGO; 20098c2ecf20Sopenharmony_ci inode->i_mode = newmode; 20108c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_ACCESS 20118c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACL; 20128c2ecf20Sopenharmony_ci attr_changed = true; 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci } else if (server->caps & NFS_CAP_MODE) { 20158c2ecf20Sopenharmony_ci nfsi->cache_validity |= save_cache_validity & 20168c2ecf20Sopenharmony_ci (NFS_INO_INVALID_OTHER 20178c2ecf20Sopenharmony_ci | NFS_INO_REVAL_FORCED); 20188c2ecf20Sopenharmony_ci cache_revalidated = false; 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_OWNER) { 20228c2ecf20Sopenharmony_ci if (!uid_eq(inode->i_uid, fattr->uid)) { 20238c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_ACCESS 20248c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACL; 20258c2ecf20Sopenharmony_ci inode->i_uid = fattr->uid; 20268c2ecf20Sopenharmony_ci attr_changed = true; 20278c2ecf20Sopenharmony_ci } 20288c2ecf20Sopenharmony_ci } else if (server->caps & NFS_CAP_OWNER) { 20298c2ecf20Sopenharmony_ci nfsi->cache_validity |= save_cache_validity & 20308c2ecf20Sopenharmony_ci (NFS_INO_INVALID_OTHER 20318c2ecf20Sopenharmony_ci | NFS_INO_REVAL_FORCED); 20328c2ecf20Sopenharmony_ci cache_revalidated = false; 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_GROUP) { 20368c2ecf20Sopenharmony_ci if (!gid_eq(inode->i_gid, fattr->gid)) { 20378c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_ACCESS 20388c2ecf20Sopenharmony_ci | NFS_INO_INVALID_ACL; 20398c2ecf20Sopenharmony_ci inode->i_gid = fattr->gid; 20408c2ecf20Sopenharmony_ci attr_changed = true; 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci } else if (server->caps & NFS_CAP_OWNER_GROUP) { 20438c2ecf20Sopenharmony_ci nfsi->cache_validity |= save_cache_validity & 20448c2ecf20Sopenharmony_ci (NFS_INO_INVALID_OTHER 20458c2ecf20Sopenharmony_ci | NFS_INO_REVAL_FORCED); 20468c2ecf20Sopenharmony_ci cache_revalidated = false; 20478c2ecf20Sopenharmony_ci } 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_NLINK) { 20508c2ecf20Sopenharmony_ci if (inode->i_nlink != fattr->nlink) { 20518c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 20528c2ecf20Sopenharmony_ci invalid |= NFS_INO_INVALID_DATA; 20538c2ecf20Sopenharmony_ci set_nlink(inode, fattr->nlink); 20548c2ecf20Sopenharmony_ci attr_changed = true; 20558c2ecf20Sopenharmony_ci } 20568c2ecf20Sopenharmony_ci } else if (server->caps & NFS_CAP_NLINK) { 20578c2ecf20Sopenharmony_ci nfsi->cache_validity |= save_cache_validity & 20588c2ecf20Sopenharmony_ci (NFS_INO_INVALID_OTHER 20598c2ecf20Sopenharmony_ci | NFS_INO_REVAL_FORCED); 20608c2ecf20Sopenharmony_ci cache_revalidated = false; 20618c2ecf20Sopenharmony_ci } 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) { 20648c2ecf20Sopenharmony_ci /* 20658c2ecf20Sopenharmony_ci * report the blocks in 512byte units 20668c2ecf20Sopenharmony_ci */ 20678c2ecf20Sopenharmony_ci inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); 20688c2ecf20Sopenharmony_ci } else if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED) 20698c2ecf20Sopenharmony_ci inode->i_blocks = fattr->du.nfs2.blocks; 20708c2ecf20Sopenharmony_ci else { 20718c2ecf20Sopenharmony_ci nfsi->cache_validity |= save_cache_validity & 20728c2ecf20Sopenharmony_ci (NFS_INO_INVALID_BLOCKS 20738c2ecf20Sopenharmony_ci | NFS_INO_REVAL_FORCED); 20748c2ecf20Sopenharmony_ci cache_revalidated = false; 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci /* Update attrtimeo value if we're out of the unstable period */ 20788c2ecf20Sopenharmony_ci if (attr_changed) { 20798c2ecf20Sopenharmony_ci invalid &= ~NFS_INO_INVALID_ATTR; 20808c2ecf20Sopenharmony_ci nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); 20818c2ecf20Sopenharmony_ci nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); 20828c2ecf20Sopenharmony_ci nfsi->attrtimeo_timestamp = now; 20838c2ecf20Sopenharmony_ci /* Set barrier to be more recent than all outstanding updates */ 20848c2ecf20Sopenharmony_ci nfsi->attr_gencount = nfs_inc_attr_generation_counter(); 20858c2ecf20Sopenharmony_ci } else { 20868c2ecf20Sopenharmony_ci if (cache_revalidated) { 20878c2ecf20Sopenharmony_ci if (!time_in_range_open(now, nfsi->attrtimeo_timestamp, 20888c2ecf20Sopenharmony_ci nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) { 20898c2ecf20Sopenharmony_ci nfsi->attrtimeo <<= 1; 20908c2ecf20Sopenharmony_ci if (nfsi->attrtimeo > NFS_MAXATTRTIMEO(inode)) 20918c2ecf20Sopenharmony_ci nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci nfsi->attrtimeo_timestamp = now; 20948c2ecf20Sopenharmony_ci } 20958c2ecf20Sopenharmony_ci /* Set the barrier to be more recent than this fattr */ 20968c2ecf20Sopenharmony_ci if ((long)(fattr->gencount - nfsi->attr_gencount) > 0) 20978c2ecf20Sopenharmony_ci nfsi->attr_gencount = fattr->gencount; 20988c2ecf20Sopenharmony_ci } 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci /* Don't invalidate the data if we were to blame */ 21018c2ecf20Sopenharmony_ci if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) 21028c2ecf20Sopenharmony_ci || S_ISLNK(inode->i_mode))) 21038c2ecf20Sopenharmony_ci invalid &= ~NFS_INO_INVALID_DATA; 21048c2ecf20Sopenharmony_ci nfs_set_cache_invalid(inode, invalid); 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci return 0; 21078c2ecf20Sopenharmony_ci out_err: 21088c2ecf20Sopenharmony_ci /* 21098c2ecf20Sopenharmony_ci * No need to worry about unhashing the dentry, as the 21108c2ecf20Sopenharmony_ci * lookup validation will know that the inode is bad. 21118c2ecf20Sopenharmony_ci * (But we fall through to invalidate the caches.) 21128c2ecf20Sopenharmony_ci */ 21138c2ecf20Sopenharmony_ci nfs_set_inode_stale_locked(inode); 21148c2ecf20Sopenharmony_ci return -ESTALE; 21158c2ecf20Sopenharmony_ci} 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_cistruct inode *nfs_alloc_inode(struct super_block *sb) 21188c2ecf20Sopenharmony_ci{ 21198c2ecf20Sopenharmony_ci struct nfs_inode *nfsi; 21208c2ecf20Sopenharmony_ci nfsi = kmem_cache_alloc(nfs_inode_cachep, GFP_KERNEL); 21218c2ecf20Sopenharmony_ci if (!nfsi) 21228c2ecf20Sopenharmony_ci return NULL; 21238c2ecf20Sopenharmony_ci nfsi->flags = 0UL; 21248c2ecf20Sopenharmony_ci nfsi->cache_validity = 0UL; 21258c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_NFS_V4) 21268c2ecf20Sopenharmony_ci nfsi->nfs4_acl = NULL; 21278c2ecf20Sopenharmony_ci#endif /* CONFIG_NFS_V4 */ 21288c2ecf20Sopenharmony_ci#ifdef CONFIG_NFS_V4_2 21298c2ecf20Sopenharmony_ci nfsi->xattr_cache = NULL; 21308c2ecf20Sopenharmony_ci#endif 21318c2ecf20Sopenharmony_ci return &nfsi->vfs_inode; 21328c2ecf20Sopenharmony_ci} 21338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_alloc_inode); 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_civoid nfs_free_inode(struct inode *inode) 21368c2ecf20Sopenharmony_ci{ 21378c2ecf20Sopenharmony_ci kmem_cache_free(nfs_inode_cachep, NFS_I(inode)); 21388c2ecf20Sopenharmony_ci} 21398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_free_inode); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_cistatic inline void nfs4_init_once(struct nfs_inode *nfsi) 21428c2ecf20Sopenharmony_ci{ 21438c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_NFS_V4) 21448c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&nfsi->open_states); 21458c2ecf20Sopenharmony_ci nfsi->delegation = NULL; 21468c2ecf20Sopenharmony_ci init_rwsem(&nfsi->rwsem); 21478c2ecf20Sopenharmony_ci nfsi->layout = NULL; 21488c2ecf20Sopenharmony_ci#endif 21498c2ecf20Sopenharmony_ci} 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_cistatic void init_once(void *foo) 21528c2ecf20Sopenharmony_ci{ 21538c2ecf20Sopenharmony_ci struct nfs_inode *nfsi = (struct nfs_inode *) foo; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci inode_init_once(&nfsi->vfs_inode); 21568c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&nfsi->open_files); 21578c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&nfsi->access_cache_entry_lru); 21588c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); 21598c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&nfsi->commit_info.list); 21608c2ecf20Sopenharmony_ci atomic_long_set(&nfsi->nrequests, 0); 21618c2ecf20Sopenharmony_ci atomic_long_set(&nfsi->commit_info.ncommit, 0); 21628c2ecf20Sopenharmony_ci atomic_set(&nfsi->commit_info.rpcs_out, 0); 21638c2ecf20Sopenharmony_ci init_rwsem(&nfsi->rmdir_sem); 21648c2ecf20Sopenharmony_ci mutex_init(&nfsi->commit_mutex); 21658c2ecf20Sopenharmony_ci nfs4_init_once(nfsi); 21668c2ecf20Sopenharmony_ci nfsi->cache_change_attribute = 0; 21678c2ecf20Sopenharmony_ci} 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_cistatic int __init nfs_init_inodecache(void) 21708c2ecf20Sopenharmony_ci{ 21718c2ecf20Sopenharmony_ci nfs_inode_cachep = kmem_cache_create("nfs_inode_cache", 21728c2ecf20Sopenharmony_ci sizeof(struct nfs_inode), 21738c2ecf20Sopenharmony_ci 0, (SLAB_RECLAIM_ACCOUNT| 21748c2ecf20Sopenharmony_ci SLAB_MEM_SPREAD|SLAB_ACCOUNT), 21758c2ecf20Sopenharmony_ci init_once); 21768c2ecf20Sopenharmony_ci if (nfs_inode_cachep == NULL) 21778c2ecf20Sopenharmony_ci return -ENOMEM; 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci return 0; 21808c2ecf20Sopenharmony_ci} 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_cistatic void nfs_destroy_inodecache(void) 21838c2ecf20Sopenharmony_ci{ 21848c2ecf20Sopenharmony_ci /* 21858c2ecf20Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 21868c2ecf20Sopenharmony_ci * destroy cache. 21878c2ecf20Sopenharmony_ci */ 21888c2ecf20Sopenharmony_ci rcu_barrier(); 21898c2ecf20Sopenharmony_ci kmem_cache_destroy(nfs_inode_cachep); 21908c2ecf20Sopenharmony_ci} 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_cistruct workqueue_struct *nfsiod_workqueue; 21938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfsiod_workqueue); 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci/* 21968c2ecf20Sopenharmony_ci * start up the nfsiod workqueue 21978c2ecf20Sopenharmony_ci */ 21988c2ecf20Sopenharmony_cistatic int nfsiod_start(void) 21998c2ecf20Sopenharmony_ci{ 22008c2ecf20Sopenharmony_ci struct workqueue_struct *wq; 22018c2ecf20Sopenharmony_ci dprintk("RPC: creating workqueue nfsiod\n"); 22028c2ecf20Sopenharmony_ci wq = alloc_workqueue("nfsiod", WQ_MEM_RECLAIM | WQ_UNBOUND, 0); 22038c2ecf20Sopenharmony_ci if (wq == NULL) 22048c2ecf20Sopenharmony_ci return -ENOMEM; 22058c2ecf20Sopenharmony_ci nfsiod_workqueue = wq; 22068c2ecf20Sopenharmony_ci return 0; 22078c2ecf20Sopenharmony_ci} 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci/* 22108c2ecf20Sopenharmony_ci * Destroy the nfsiod workqueue 22118c2ecf20Sopenharmony_ci */ 22128c2ecf20Sopenharmony_cistatic void nfsiod_stop(void) 22138c2ecf20Sopenharmony_ci{ 22148c2ecf20Sopenharmony_ci struct workqueue_struct *wq; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci wq = nfsiod_workqueue; 22178c2ecf20Sopenharmony_ci if (wq == NULL) 22188c2ecf20Sopenharmony_ci return; 22198c2ecf20Sopenharmony_ci nfsiod_workqueue = NULL; 22208c2ecf20Sopenharmony_ci destroy_workqueue(wq); 22218c2ecf20Sopenharmony_ci} 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ciunsigned int nfs_net_id; 22248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(nfs_net_id); 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_cistatic int nfs_net_init(struct net *net) 22278c2ecf20Sopenharmony_ci{ 22288c2ecf20Sopenharmony_ci struct nfs_net *nn = net_generic(net, nfs_net_id); 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci nfs_clients_init(net); 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci if (!rpc_proc_register(net, &nn->rpcstats)) { 22338c2ecf20Sopenharmony_ci nfs_clients_exit(net); 22348c2ecf20Sopenharmony_ci return -ENOMEM; 22358c2ecf20Sopenharmony_ci } 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci return nfs_fs_proc_net_init(net); 22388c2ecf20Sopenharmony_ci} 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_cistatic void nfs_net_exit(struct net *net) 22418c2ecf20Sopenharmony_ci{ 22428c2ecf20Sopenharmony_ci rpc_proc_unregister(net, "nfs"); 22438c2ecf20Sopenharmony_ci nfs_fs_proc_net_exit(net); 22448c2ecf20Sopenharmony_ci nfs_clients_exit(net); 22458c2ecf20Sopenharmony_ci} 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_cistatic struct pernet_operations nfs_net_ops = { 22488c2ecf20Sopenharmony_ci .init = nfs_net_init, 22498c2ecf20Sopenharmony_ci .exit = nfs_net_exit, 22508c2ecf20Sopenharmony_ci .id = &nfs_net_id, 22518c2ecf20Sopenharmony_ci .size = sizeof(struct nfs_net), 22528c2ecf20Sopenharmony_ci}; 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci/* 22558c2ecf20Sopenharmony_ci * Initialize NFS 22568c2ecf20Sopenharmony_ci */ 22578c2ecf20Sopenharmony_cistatic int __init init_nfs_fs(void) 22588c2ecf20Sopenharmony_ci{ 22598c2ecf20Sopenharmony_ci int err; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci err = nfs_sysfs_init(); 22628c2ecf20Sopenharmony_ci if (err < 0) 22638c2ecf20Sopenharmony_ci goto out10; 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci err = register_pernet_subsys(&nfs_net_ops); 22668c2ecf20Sopenharmony_ci if (err < 0) 22678c2ecf20Sopenharmony_ci goto out9; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci err = nfs_fscache_register(); 22708c2ecf20Sopenharmony_ci if (err < 0) 22718c2ecf20Sopenharmony_ci goto out8; 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci err = nfsiod_start(); 22748c2ecf20Sopenharmony_ci if (err) 22758c2ecf20Sopenharmony_ci goto out7; 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci err = nfs_fs_proc_init(); 22788c2ecf20Sopenharmony_ci if (err) 22798c2ecf20Sopenharmony_ci goto out6; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci err = nfs_init_nfspagecache(); 22828c2ecf20Sopenharmony_ci if (err) 22838c2ecf20Sopenharmony_ci goto out5; 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci err = nfs_init_inodecache(); 22868c2ecf20Sopenharmony_ci if (err) 22878c2ecf20Sopenharmony_ci goto out4; 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci err = nfs_init_readpagecache(); 22908c2ecf20Sopenharmony_ci if (err) 22918c2ecf20Sopenharmony_ci goto out3; 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci err = nfs_init_writepagecache(); 22948c2ecf20Sopenharmony_ci if (err) 22958c2ecf20Sopenharmony_ci goto out2; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci err = nfs_init_directcache(); 22988c2ecf20Sopenharmony_ci if (err) 22998c2ecf20Sopenharmony_ci goto out1; 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci err = register_nfs_fs(); 23028c2ecf20Sopenharmony_ci if (err) 23038c2ecf20Sopenharmony_ci goto out0; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci return 0; 23068c2ecf20Sopenharmony_ciout0: 23078c2ecf20Sopenharmony_ci nfs_destroy_directcache(); 23088c2ecf20Sopenharmony_ciout1: 23098c2ecf20Sopenharmony_ci nfs_destroy_writepagecache(); 23108c2ecf20Sopenharmony_ciout2: 23118c2ecf20Sopenharmony_ci nfs_destroy_readpagecache(); 23128c2ecf20Sopenharmony_ciout3: 23138c2ecf20Sopenharmony_ci nfs_destroy_inodecache(); 23148c2ecf20Sopenharmony_ciout4: 23158c2ecf20Sopenharmony_ci nfs_destroy_nfspagecache(); 23168c2ecf20Sopenharmony_ciout5: 23178c2ecf20Sopenharmony_ci nfs_fs_proc_exit(); 23188c2ecf20Sopenharmony_ciout6: 23198c2ecf20Sopenharmony_ci nfsiod_stop(); 23208c2ecf20Sopenharmony_ciout7: 23218c2ecf20Sopenharmony_ci nfs_fscache_unregister(); 23228c2ecf20Sopenharmony_ciout8: 23238c2ecf20Sopenharmony_ci unregister_pernet_subsys(&nfs_net_ops); 23248c2ecf20Sopenharmony_ciout9: 23258c2ecf20Sopenharmony_ci nfs_sysfs_exit(); 23268c2ecf20Sopenharmony_ciout10: 23278c2ecf20Sopenharmony_ci return err; 23288c2ecf20Sopenharmony_ci} 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_cistatic void __exit exit_nfs_fs(void) 23318c2ecf20Sopenharmony_ci{ 23328c2ecf20Sopenharmony_ci nfs_destroy_directcache(); 23338c2ecf20Sopenharmony_ci nfs_destroy_writepagecache(); 23348c2ecf20Sopenharmony_ci nfs_destroy_readpagecache(); 23358c2ecf20Sopenharmony_ci nfs_destroy_inodecache(); 23368c2ecf20Sopenharmony_ci nfs_destroy_nfspagecache(); 23378c2ecf20Sopenharmony_ci nfs_fscache_unregister(); 23388c2ecf20Sopenharmony_ci unregister_pernet_subsys(&nfs_net_ops); 23398c2ecf20Sopenharmony_ci unregister_nfs_fs(); 23408c2ecf20Sopenharmony_ci nfs_fs_proc_exit(); 23418c2ecf20Sopenharmony_ci nfsiod_stop(); 23428c2ecf20Sopenharmony_ci nfs_sysfs_exit(); 23438c2ecf20Sopenharmony_ci} 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci/* Not quite true; I just maintain it */ 23468c2ecf20Sopenharmony_ciMODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>"); 23478c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 23488c2ecf20Sopenharmony_cimodule_param(enable_ino64, bool, 0644); 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_cimodule_init(init_nfs_fs) 23518c2ecf20Sopenharmony_cimodule_exit(exit_nfs_fs) 2352