📄 inode.c
字号:
*/static voidnfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr){ /* * Check whether the mode has been set, as we only want to * do this once. (We don't allow inodes to change types.) */ if (inode->i_mode == 0) { NFS_FILEID(inode) = fattr->fileid; NFS_FSID(inode) = fattr->fsid; inode->i_mode = fattr->mode; /* Why so? Because we want revalidate for devices/FIFOs, and * that's precisely what we have in nfs_file_inode_operations. */ inode->i_op = &nfs_file_inode_operations; if (S_ISREG(inode->i_mode)) { inode->i_fop = &nfs_file_operations; inode->i_data.a_ops = &nfs_file_aops; } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &nfs_dir_inode_operations; inode->i_fop = &nfs_dir_operations; } else if (S_ISLNK(inode->i_mode)) inode->i_op = &nfs_symlink_inode_operations; else init_special_inode(inode, inode->i_mode, fattr->rdev); /* * Preset the size and mtime, as there's no need * to invalidate the caches. */ inode->i_size = nfs_size_to_loff_t(fattr->size); inode->i_mtime = nfs_time_to_secs(fattr->mtime); inode->i_atime = nfs_time_to_secs(fattr->atime); inode->i_ctime = nfs_time_to_secs(fattr->ctime); NFS_CACHE_CTIME(inode) = fattr->ctime; NFS_CACHE_MTIME(inode) = fattr->mtime; NFS_CACHE_ATIME(inode) = fattr->atime; NFS_CACHE_ISIZE(inode) = fattr->size; NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; memcpy(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)); } nfs_refresh_inode(inode, fattr);}struct nfs_find_desc { struct nfs_fh *fh; struct nfs_fattr *fattr;};/* * In NFSv3 we can have 64bit inode numbers. In order to support * this, and re-exported directories (also seen in NFSv2) * we are forced to allow 2 different inodes to have the same * i_ino. */static intnfs_find_actor(struct inode *inode, unsigned long ino, void *opaque){ struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque; struct nfs_fh *fh = desc->fh; struct nfs_fattr *fattr = desc->fattr; if (NFS_FSID(inode) != fattr->fsid) return 0; if (NFS_FILEID(inode) != fattr->fileid) return 0; if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0) return 0; return 1;}intnfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr){ /* Empty inodes are not stale */ if (!inode->i_mode) return 0; if ((fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT)) return 1; if (is_bad_inode(inode)) return 1; /* Has the filehandle changed? If so is the old one stale? */ if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 && __nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE) return 1; return 0;}/* * This is our own version of iget that looks up inodes by file handle * instead of inode number. We use this technique instead of using * the vfs read_inode function because there is no way to pass the * file handle or current attributes into the read_inode function. * */struct inode *nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle, struct nfs_fattr *fattr){ struct super_block *sb = dentry->d_sb; dprintk("NFS: nfs_fhget(%s/%s fileid=%Ld)\n", dentry->d_parent->d_name.name, dentry->d_name.name, (long long)fattr->fileid); return __nfs_fhget(sb, fhandle, fattr);}/* * Look up the inode by super block and fattr->fileid. */static struct inode *__nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr){ struct nfs_find_desc desc = { fh, fattr }; struct inode *inode = NULL; unsigned long ino; if ((fattr->valid & NFS_ATTR_FATTR) == 0) goto out_no_inode; if (!fattr->nlink) { printk("NFS: Buggy server - nlink == 0!\n"); goto out_no_inode; } ino = nfs_fattr_to_ino_t(fattr); if (!(inode = iget4(sb, ino, nfs_find_actor, &desc))) goto out_no_inode; nfs_fill_inode(inode, fh, fattr); dprintk("NFS: __nfs_fhget(%x/%Ld ct=%d)\n", inode->i_dev, (long long)NFS_FILEID(inode), atomic_read(&inode->i_count));out: return inode;out_no_inode: printk("__nfs_fhget: iget failed\n"); goto out;}intnfs_notify_change(struct dentry *dentry, struct iattr *attr){ struct inode *inode = dentry->d_inode; struct nfs_fattr fattr; int error; /* * Make sure the inode is up-to-date. */ error = nfs_revalidate(dentry); if (error) {#ifdef NFS_PARANOIAprintk("nfs_notify_change: revalidate failed, error=%d\n", error);#endif goto out; } if (!S_ISREG(inode->i_mode)) attr->ia_valid &= ~ATTR_SIZE; error = nfs_wb_all(inode); if (error) goto out; error = NFS_PROTO(inode)->setattr(inode, &fattr, attr); if (error) goto out; /* * If we changed the size or mtime, update the inode * now to avoid invalidating the page cache. */ if (attr->ia_valid & ATTR_SIZE) { 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; } 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);}/* * 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; unlock_kernel(); return 0;}int nfs_release(struct inode *inode, struct file *filp){ struct rpc_auth *auth; struct rpc_cred *cred; lock_kernel(); auth = NFS_CLIENT(inode)->cl_auth; cred = nfs_file_cred(filp); if (cred) rpcauth_releasecred(auth, 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 = 0; 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) || NFS_STALE(inode)) { unlock_kernel(); return -ESTALE; } while (NFS_REVALIDATING(inode)) { status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING); if (status < 0) { unlock_kernel(); return status; } 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; 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));out: NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING; wake_up(&inode->i_wait); out_nowait: unlock_kernel(); return status;}/* * 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. */intnfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr){ __u64 new_size, new_mtime; loff_t new_isize; int invalid = 0; int error = -EIO; if (!inode || !fattr) { printk(KERN_ERR "nfs_refresh_inode: inode or fattr is NULL\n"); goto out; } if (inode->i_mode == 0) { printk(KERN_ERR "nfs_refresh_inode: empty inode\n"); goto out; } if ((fattr->valid & NFS_ATTR_FATTR) == 0) goto out; if (is_bad_inode(inode)) goto out; 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; } /* * 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); error = 0; /* * 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); /* If we've been messing around with atime, don't * update it. Save the server value in NFS_CACHE_ATIME. */ NFS_CACHE_ATIME(inode) = fattr->atime; if (time_before(inode->i_atime, nfs_time_to_secs(fattr->atime))) inode->i_atime = nfs_time_to_secs(fattr->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);out: return error;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); goto out;}/* * 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);/* * Initialize NFS */intinit_nfs_fs(void){ int err; err = nfs_init_nfspagecache(); if (err) return err; err = nfs_init_readpagecache(); if (err) return err;#ifdef CONFIG_PROC_FS rpc_proc_register(&nfs_rpcstat);#endif return register_filesystem(&nfs_fs_type);}/* * Every kernel module contains stuff like this. */#ifdef MODULEEXPORT_NO_SYMBOLS;/* Not quite true; I just maintain it */MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");intinit_module(void){ return init_nfs_fs();}voidcleanup_module(void){ nfs_destroy_readpagecache(); nfs_destroy_nfspagecache();#ifdef CONFIG_PROC_FS rpc_proc_unregister("nfs");#endif unregister_filesystem(&nfs_fs_type);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -