Skip to content
Snippets Groups Projects
inode.c 34.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ATIME
    			| NFS_INO_REVAL_PAGECACHE);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	/* Do atomic weak cache consistency updates */
    	nfs_wcc_update_inode(inode, fattr);
    
    
    	/* More cache consistency checks */
    	if (!(fattr->valid & NFS_ATTR_FATTR_V4)) {
    		/* NFSv2/v3: Check if the mtime agrees */
    		if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
    			dprintk("NFS: mtime change on server for file %s/%ld\n",
    					inode->i_sb->s_id, inode->i_ino);
    			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
    			nfsi->cache_change_attribute = now;
    		}
    		/* If ctime has changed we should definitely clear access+acl caches */
    
    		if (!timespec_equal(&inode->i_ctime, &fattr->ctime))
    
    			invalid |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
    	} else if (nfsi->change_attr != fattr->change_attr) {
    		dprintk("NFS: change_attr change on server for file %s/%ld\n",
    				inode->i_sb->s_id, inode->i_ino);
    		invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
    		nfsi->cache_change_attribute = now;
    	}
    
    
    	/* Check if our cached file size is stale */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     	new_isize = nfs_size_to_loff_t(fattr->size);
    	cur_isize = i_size_read(inode);
    
    	if (new_isize != cur_isize) {
    
    		/* Do we perhaps have any outstanding writes, or has
    		 * the file grown beyond our last write? */
    		if (nfsi->npages == 0 || new_isize > cur_isize) {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			inode->i_size = new_isize;
    			invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
    		}
    
    		dprintk("NFS: isize change on server for file %s/%ld\n",
    				inode->i_sb->s_id, inode->i_ino);
    
    	memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
    	memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
    
    	nfsi->change_attr = fattr->change_attr;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
    	    inode->i_uid != fattr->uid ||
    	    inode->i_gid != fattr->gid)
    
    		invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	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 | NFS_ATTR_FATTR_V4)) {
    		/*
    		 * report the blocks in 512byte units
    		 */
    		inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
     	} else {
     		inode->i_blocks = fattr->du.nfs2.blocks;
     	}
    
    	/* Update attrtimeo value if we're out of the unstable period */
    	if (invalid & NFS_INO_INVALID_ATTR) {
    
    		nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
    
    		nfsi->attrtimeo_timestamp = now;
    
    	} else if (!time_in_range(now, nfsi->attrtimeo_timestamp, nfsi->attrtimeo_timestamp + nfsi->attrtimeo)) {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
    			nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
    
    		nfsi->attrtimeo_timestamp = now;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	/* Don't invalidate the data if we were to blame */
    	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
    				|| S_ISLNK(inode->i_mode)))
    		invalid &= ~NFS_INO_INVALID_DATA;
    
    	if (!nfs_have_delegation(inode, FMODE_READ) ||
    			(nfsi->cache_validity & NFS_INO_REVAL_FORCED))
    
    		nfsi->cache_validity |= invalid;
    
    	nfsi->cache_validity &= ~NFS_INO_REVAL_FORCED;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	return 0;
     out_changed:
    	/*
    	 * Big trouble! The inode has become a different object.
    	 */
    	printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n",
    			__FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	/*
    	 * 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);
    	return -ESTALE;
    
    
     out_fileid:
    	printk(KERN_ERR "NFS: server %s error: fileid changed\n"
    		"fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
    
    		NFS_SERVER(inode)->nfs_client->cl_hostname, inode->i_sb->s_id,
    
    		(long long)nfsi->fileid, (long long)fattr->fileid);
    	goto out_err;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #ifdef CONFIG_NFS_V4
    
    /*
     * Clean out any remaining NFSv4 state that might be left over due
     * to open() calls that passed nfs_atomic_lookup, but failed to call
     * nfs_open().
     */
    
    David Howells's avatar
    David Howells committed
    void nfs4_clear_inode(struct inode *inode)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	/* If we are holding a delegation, return it! */
    
    	nfs_inode_return_delegation(inode);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	/* First call standard NFS clear_inode() code */
    	nfs_clear_inode(inode);
    }
    #endif
    
    
    David Howells's avatar
    David Howells committed
    struct inode *nfs_alloc_inode(struct super_block *sb)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct nfs_inode *nfsi;
    
    	nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, GFP_KERNEL);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (!nfsi)
    		return NULL;
    
    	nfsi->flags = 0UL;
    	nfsi->cache_validity = 0UL;
    
    #ifdef CONFIG_NFS_V3_ACL
    	nfsi->acl_access = ERR_PTR(-EAGAIN);
    	nfsi->acl_default = ERR_PTR(-EAGAIN);
    #endif
    
    #ifdef CONFIG_NFS_V4
    	nfsi->nfs4_acl = NULL;
    #endif /* CONFIG_NFS_V4 */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return &nfsi->vfs_inode;
    }
    
    
    David Howells's avatar
    David Howells committed
    void nfs_destroy_inode(struct inode *inode)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	kmem_cache_free(nfs_inode_cachep, NFS_I(inode));
    }
    
    
    Andrew Morton's avatar
    Andrew Morton committed
    static inline void nfs4_init_once(struct nfs_inode *nfsi)
    {
    #ifdef CONFIG_NFS_V4
    	INIT_LIST_HEAD(&nfsi->open_states);
    	nfsi->delegation = NULL;
    	nfsi->delegation_state = 0;
    	init_rwsem(&nfsi->rwsem);
    #endif
    }
    
    static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct nfs_inode *nfsi = (struct nfs_inode *) foo;
    
    
    	inode_init_once(&nfsi->vfs_inode);
    	INIT_LIST_HEAD(&nfsi->open_files);
    	INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
    	INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
    	INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
    	atomic_set(&nfsi->data_updates, 0);
    	nfsi->ncommit = 0;
    	nfsi->npages = 0;
    	nfs4_init_once(nfsi);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    David Howells's avatar
    David Howells committed
    static int __init nfs_init_inodecache(void)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
    					     sizeof(struct nfs_inode),
    
    					     0, (SLAB_RECLAIM_ACCOUNT|
    						SLAB_MEM_SPREAD),
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (nfs_inode_cachep == NULL)
    		return -ENOMEM;
    
    	return 0;
    }
    
    
    static void nfs_destroy_inodecache(void)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	kmem_cache_destroy(nfs_inode_cachep);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    /*
     * Initialize NFS
     */
    static int __init init_nfs_fs(void)
    {
    	int err;
    
    
    	err = nfs_fs_proc_init();
    	if (err)
    		goto out5;
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	err = nfs_init_nfspagecache();
    	if (err)
    		goto out4;
    
    	err = nfs_init_inodecache();
    	if (err)
    		goto out3;
    
    	err = nfs_init_readpagecache();
    	if (err)
    		goto out2;
    
    	err = nfs_init_writepagecache();
    	if (err)
    		goto out1;
    
    	err = nfs_init_directcache();
    	if (err)
    		goto out0;
    
    #ifdef CONFIG_PROC_FS
    	rpc_proc_register(&nfs_rpcstat);
    #endif
    
    David Howells's avatar
    David Howells committed
    	if ((err = register_nfs_fs()) != 0)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		goto out;
    	return 0;
    out:
    #ifdef CONFIG_PROC_FS
    	rpc_proc_unregister("nfs");
    #endif
    	nfs_destroy_directcache();
    
    out0:
    	nfs_destroy_writepagecache();
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    out1:
    	nfs_destroy_readpagecache();
    out2:
    	nfs_destroy_inodecache();
    out3:
    	nfs_destroy_nfspagecache();
    out4:
    
    	nfs_fs_proc_exit();
    out5:
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return err;
    }
    
    static void __exit exit_nfs_fs(void)
    {
    	nfs_destroy_directcache();
    	nfs_destroy_writepagecache();
    	nfs_destroy_readpagecache();
    	nfs_destroy_inodecache();
    	nfs_destroy_nfspagecache();
    #ifdef CONFIG_PROC_FS
    	rpc_proc_unregister("nfs");
    #endif
    
    David Howells's avatar
    David Howells committed
    	unregister_nfs_fs();
    
    	nfs_fs_proc_exit();
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    /* 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)