📄 inode.c
字号:
if (attr->ia_size != fattr.size) printk("nfs_notify_change: attr=%Ld, fattr=%Ld??\n", (long long) attr->ia_size, (long long)fattr.size); vmtruncate(inode, attr->ia_size); } /* * If we changed the size or mtime, update the inode * now to avoid invalidating the page cache. */ if (!(fattr.valid & NFS_ATTR_WCC)) { fattr.pre_size = NFS_CACHE_ISIZE(inode); fattr.pre_mtime = NFS_CACHE_MTIME(inode); fattr.pre_ctime = NFS_CACHE_CTIME(inode); fattr.valid |= NFS_ATTR_WCC; } /* Force an attribute cache update */ NFS_CACHEINV(inode); error = nfs_refresh_inode(inode, &fattr);out: return error;}/* * Wait for the inode to get unlocked. * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING). */intnfs_wait_on_inode(struct inode *inode, int flag){ struct rpc_clnt *clnt = NFS_CLIENT(inode); int error; if (!(NFS_FLAGS(inode) & flag)) return 0; atomic_inc(&inode->i_count); error = nfs_wait_event(clnt, inode->i_wait, !(NFS_FLAGS(inode) & flag)); iput(inode); return error;}/* * Externally visible revalidation function */intnfs_revalidate(struct dentry *dentry){ struct inode *inode = dentry->d_inode; return nfs_revalidate_inode(NFS_SERVER(inode), inode);}/* * Ensure that mmap has a recent RPC credential for use when writing out * shared pages */static inline voidnfs_set_mmcred(struct inode *inode, struct rpc_cred *cred){ struct rpc_cred **p = &NFS_I(inode)->mm_cred, *oldcred = *p; *p = get_rpccred(cred); if (oldcred) put_rpccred(oldcred);}/* * These are probably going to contain hooks for * allocating and releasing RPC credentials for * the file. I'll have to think about Tronds patch * a bit more.. */int nfs_open(struct inode *inode, struct file *filp){ struct rpc_auth *auth; struct rpc_cred *cred; lock_kernel(); auth = NFS_CLIENT(inode)->cl_auth; cred = rpcauth_lookupcred(auth, 0); filp->private_data = cred; if (filp->f_mode & FMODE_WRITE) nfs_set_mmcred(inode, cred); unlock_kernel(); return 0;}int nfs_release(struct inode *inode, struct file *filp){ struct rpc_cred *cred; lock_kernel(); cred = nfs_file_cred(filp); if (cred) put_rpccred(cred); unlock_kernel(); return 0;}/* * This function is called whenever some part of NFS notices that * the cached attributes have to be refreshed. */int__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode){ int status = -ESTALE; struct nfs_fattr fattr; dfprintk(PAGECACHE, "NFS: revalidating (%x/%Ld)\n", inode->i_dev, (long long)NFS_FILEID(inode)); lock_kernel(); if (!inode || is_bad_inode(inode)) goto out_nowait; if (NFS_STALE(inode) && inode != inode->i_sb->s_root->d_inode) goto out_nowait; while (NFS_REVALIDATING(inode)) { status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING); if (status < 0) goto out_nowait; if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) { status = NFS_STALE(inode) ? -ESTALE : 0; goto out_nowait; } } NFS_FLAGS(inode) |= NFS_INO_REVALIDATING; status = NFS_PROTO(inode)->getattr(inode, &fattr); if (status) { dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n", inode->i_dev, (long long)NFS_FILEID(inode), status); if (status == -ESTALE) { NFS_FLAGS(inode) |= NFS_INO_STALE; if (inode != inode->i_sb->s_root->d_inode) remove_inode_hash(inode); } goto out; } status = nfs_refresh_inode(inode, &fattr); if (status) { dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) refresh failed, error=%d\n", inode->i_dev, (long long)NFS_FILEID(inode), status); goto out; } dfprintk(PAGECACHE, "NFS: (%x/%Ld) revalidation complete\n", inode->i_dev, (long long)NFS_FILEID(inode)); NFS_FLAGS(inode) &= ~NFS_INO_STALE;out: NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING; wake_up(&inode->i_wait); out_nowait: unlock_kernel(); return status;}/* * nfs_fattr_obsolete - Test if attribute data is newer than cached data * @inode: inode * @fattr: attributes to test * * Avoid stuffing the attribute cache with obsolete information. * We always accept updates if the attribute cache timed out, or if * fattr->ctime is newer than our cached value. * If fattr->ctime matches the cached value, we still accept the update * if it increases the file size. */static inlineint nfs_fattr_obsolete(struct inode *inode, struct nfs_fattr *fattr){ s64 cdif; if (time_after(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) goto out_valid; if ((cdif = (s64)fattr->ctime - (s64)NFS_CACHE_CTIME(inode)) > 0) goto out_valid; /* Ugh... */ if (cdif == 0 && fattr->size > NFS_CACHE_ISIZE(inode)) goto out_valid; return -1; out_valid: return 0;}/* * Many nfs protocol calls return the new file attributes after * an operation. Here we update the inode to reflect the state * of the server's inode. * * This is a bit tricky because we have to make sure all dirty pages * have been sent off to the server before calling invalidate_inode_pages. * To make sure no other process adds more write requests while we try * our best to flush them, we make them sleep during the attribute refresh. * * A very similar scenario holds for the dir cache. */int__nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr){ __u64 new_size, new_mtime; loff_t new_isize; time_t new_atime; int invalid = 0; dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d info=0x%x)\n", inode->i_dev, inode->i_ino, atomic_read(&inode->i_count), fattr->valid); if (NFS_FSID(inode) != fattr->fsid || NFS_FILEID(inode) != fattr->fileid) { printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n" "expected (0x%Lx/0x%Lx), got (0x%Lx/0x%Lx)\n", (long long)NFS_FSID(inode), (long long)NFS_FILEID(inode), (long long)fattr->fsid, (long long)fattr->fileid); goto out_err; } /* * Make sure the inode's type hasn't changed. */ if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) goto out_changed; new_mtime = fattr->mtime; new_size = fattr->size; new_isize = nfs_size_to_loff_t(fattr->size); new_atime = nfs_time_to_secs(fattr->atime); /* Avoid races */ if (nfs_fattr_obsolete(inode, fattr)) goto out_nochange; /* * Update the read time so we don't revalidate too often. */ NFS_READTIME(inode) = jiffies; /* * Note: NFS_CACHE_ISIZE(inode) reflects the state of the cache. * NOT inode->i_size!!! */ if (NFS_CACHE_ISIZE(inode) != new_size) {#ifdef NFS_DEBUG_VERBOSE printk(KERN_DEBUG "NFS: isize change on %x/%ld\n", inode->i_dev, inode->i_ino);#endif invalid = 1; } /* * Note: we don't check inode->i_mtime since pipes etc. * can change this value in VFS without requiring a * cache revalidation. */ if (NFS_CACHE_MTIME(inode) != new_mtime) {#ifdef NFS_DEBUG_VERBOSE printk(KERN_DEBUG "NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);#endif invalid = 1; } /* Check Weak Cache Consistency data. * If size and mtime match the pre-operation values, we can * assume that any attribute changes were caused by our NFS * operation, so there's no need to invalidate the caches. */ if ((fattr->valid & NFS_ATTR_WCC) && NFS_CACHE_ISIZE(inode) == fattr->pre_size && NFS_CACHE_MTIME(inode) == fattr->pre_mtime) { invalid = 0; } /* * If we have pending writebacks, things can get * messy. */ if (nfs_have_writebacks(inode) && new_isize < inode->i_size) new_isize = inode->i_size; NFS_CACHE_CTIME(inode) = fattr->ctime; inode->i_ctime = nfs_time_to_secs(fattr->ctime); inode->i_atime = new_atime; NFS_CACHE_MTIME(inode) = new_mtime; inode->i_mtime = nfs_time_to_secs(new_mtime); NFS_CACHE_ISIZE(inode) = new_size; inode->i_size = new_isize; inode->i_mode = fattr->mode; inode->i_nlink = fattr->nlink; inode->i_uid = fattr->uid; inode->i_gid = fattr->gid; if (fattr->valid & NFS_ATTR_FATTR_V3) { /* * report the blocks in 512byte units */ inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); inode->i_blksize = inode->i_sb->s_blocksize; } else { inode->i_blocks = fattr->du.nfs2.blocks; inode->i_blksize = fattr->du.nfs2.blocksize; } inode->i_rdev = 0; if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) inode->i_rdev = to_kdev_t(fattr->rdev); /* Update attrtimeo value */ if (!invalid && time_after(jiffies, NFS_ATTRTIMEO_UPDATE(inode)+NFS_ATTRTIMEO(inode))) { if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode)) NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; } if (invalid) nfs_zap_caches(inode); return 0; out_nochange: if (new_atime - inode->i_atime > 0) inode->i_atime = new_atime; return 0; out_changed: /* * Big trouble! The inode has become a different object. */#ifdef NFS_PARANOIA printk(KERN_DEBUG "nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n", inode->i_ino, inode->i_mode, fattr->mode);#endif /* * No need to worry about unhashing the dentry, as the * lookup validation will know that the inode is bad. * (But we fall through to invalidate the caches.) */ nfs_invalidate_inode(inode); out_err: return -EIO;}/* * File system information */static DECLARE_FSTYPE(nfs_fs_type, "nfs", nfs_read_super, FS_ODD_RENAME);extern int nfs_init_nfspagecache(void);extern void nfs_destroy_nfspagecache(void);extern int nfs_init_readpagecache(void);extern int nfs_destroy_readpagecache(void);extern int nfs_init_writepagecache(void);extern int nfs_destroy_writepagecache(void);/* * Initialize NFS */static int __init init_nfs_fs(void){ int err; err = nfs_init_nfspagecache(); if (err) return err; err = nfs_init_readpagecache(); if (err) return err; err = nfs_init_writepagecache(); if (err) return err;#ifdef CONFIG_PROC_FS rpc_proc_register(&nfs_rpcstat);#endif return register_filesystem(&nfs_fs_type);}static void __exit exit_nfs_fs(void){ nfs_destroy_writepagecache(); nfs_destroy_readpagecache(); nfs_destroy_nfspagecache();#ifdef CONFIG_PROC_FS rpc_proc_unregister("nfs");#endif unregister_filesystem(&nfs_fs_type);}EXPORT_NO_SYMBOLS;/* Not quite true; I just maintain it */MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");MODULE_LICENSE("GPL");module_init(init_nfs_fs)module_exit(exit_nfs_fs)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -