Exemplo n.º 1
0
void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
{
	int was_empty;

	if (!inode || !fattr) {
		printk("nfs_refresh_inode: inode or fattr is NULL\n");
		return;
	}
	if (inode->i_ino != fattr->fileid) {
		printk("nfs_refresh_inode: inode number mismatch\n");
		return;
	}
	was_empty = (inode->i_mode == 0);
	
	/*
	 * Some (broken?) NFS servers return 0 as the file type.
	 * We'll assume that 0 means the file type has not changed.
	 */
	if(!(fattr->mode & S_IFMT)){
		inode->i_mode = (inode->i_mode & S_IFMT) |
				(fattr->mode & ~S_IFMT);
	}else{
		inode->i_mode = fattr->mode;
	}
	inode->i_nlink = fattr->nlink;
	inode->i_uid = fattr->uid;
	inode->i_gid = fattr->gid;

	/* Size changed from outside: invalidate caches on next read */
	if (inode->i_size != fattr->size)
		NFS_CACHEINV(inode);
	if (NFS_OLDMTIME(inode) != fattr->mtime.seconds)
		NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
	inode->i_size = fattr->size;
	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
		inode->i_rdev = to_kdev_t(fattr->rdev);
	else
		inode->i_rdev = 0;
	inode->i_blocks = fattr->blocks;
	inode->i_atime = fattr->atime.seconds;
	inode->i_mtime = fattr->mtime.seconds;
	inode->i_ctime = fattr->ctime.seconds;
	if (S_ISREG(inode->i_mode))
		inode->i_op = &nfs_file_inode_operations;
	else if (S_ISDIR(inode->i_mode))
		inode->i_op = &nfs_dir_inode_operations;
	else if (S_ISLNK(inode->i_mode))
		inode->i_op = &nfs_symlink_inode_operations;
	else if (S_ISCHR(inode->i_mode))
		inode->i_op = &chrdev_inode_operations;
	else if (S_ISBLK(inode->i_mode))
		inode->i_op = &blkdev_inode_operations;
	else if (S_ISFIFO(inode->i_mode)) {
		if (was_empty)
			init_fifo(inode);
	} else
		inode->i_op = NULL;
	nfs_lookup_cache_refresh(inode, fattr);
}
Exemplo n.º 2
0
static inline void revalidate_dir(struct nfs_server * server, struct inode * dir)
{
	struct nfs_fattr fattr;

	if (jiffies - NFS_READTIME(dir) < NFS_ATTRTIMEO(dir))
		return;

	NFS_READTIME(dir) = jiffies;
	if (nfs_proc_getattr(server, NFS_FH(dir), &fattr) == 0) {
		nfs_refresh_inode(dir, &fattr);
		if (fattr.mtime.seconds == NFS_OLDMTIME(dir)) {
			if ((NFS_ATTRTIMEO(dir) <<= 1) > server->acdirmax)
				NFS_ATTRTIMEO(dir) = server->acdirmax;
			return;
		}
		NFS_OLDMTIME(dir) = fattr.mtime.seconds;
	}
	/* invalidate directory cache here when we _really_ start caching */
}
Exemplo n.º 3
0
/*
 * The "read_inode" function doesn't actually do anything:
 * the real data is filled in later in nfs_fhget. Here we
 * just mark the cache times invalid, and zero out i_mode
 * (the latter makes "nfs_refresh_inode" do the right thing
 * wrt pipe inodes)
 */
static void
nfs_read_inode(struct inode * inode)
{
    inode->i_blksize = inode->i_sb->s_blocksize;
    inode->i_mode = 0;
    inode->i_rdev = 0;
    inode->i_op = NULL;
    NFS_CACHEINV(inode);
    NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
}
Exemplo n.º 4
0
/*
 * Invalidate the local caches
 */
static void
nfs_zap_caches(struct inode *inode)
{
    NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
    NFS_CACHEINV(inode);

    if (S_ISDIR(inode->i_mode))
        nfs_invalidate_dircache(inode);
    else
        invalidate_inode_pages(inode);
}
Exemplo n.º 5
0
/*
 * The "read_inode" function doesn't actually do anything:
 * the real data is filled in later in nfs_fhget. Here we
 * just mark the cache times invalid, and zero out i_mode
 * (the latter makes "nfs_refresh_inode" do the right thing
 * wrt pipe inodes)
 */
static void
nfs_read_inode(struct inode * inode)
{
	inode->i_blksize = inode->i_sb->s_blocksize;
	inode->i_mode = 0;
	inode->i_rdev = 0;
	/* We can't support UPDATE_ATIME(), since the server will reset it */
	inode->i_flags |= S_NOATIME;
	INIT_LIST_HEAD(&inode->u.nfs_i.read);
	INIT_LIST_HEAD(&inode->u.nfs_i.dirty);
	INIT_LIST_HEAD(&inode->u.nfs_i.commit);
	INIT_LIST_HEAD(&inode->u.nfs_i.writeback);
	NFS_CACHEINV(inode);
	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
	NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
}
Exemplo n.º 6
0
/*
 * The "read_inode" function doesn't actually do anything:
 * the real data is filled in later in nfs_fhget. Here we
 * just mark the cache times invalid, and zero out i_mode
 * (the latter makes "nfs_refresh_inode" do the right thing
 * wrt pipe inodes)
 */
static void
nfs_read_inode(struct inode * inode)
{
	inode->i_blksize = inode->i_sb->s_blocksize;
	inode->i_mode = 0;
	inode->i_rdev = 0;
	NFS_FILEID(inode) = 0;
	NFS_FSID(inode) = 0;
	INIT_LIST_HEAD(&inode->u.nfs_i.read);
	INIT_LIST_HEAD(&inode->u.nfs_i.dirty);
	INIT_LIST_HEAD(&inode->u.nfs_i.commit);
	INIT_LIST_HEAD(&inode->u.nfs_i.writeback);
	inode->u.nfs_i.nread = 0;
	inode->u.nfs_i.ndirty = 0;
	inode->u.nfs_i.ncommit = 0;
	inode->u.nfs_i.npages = 0;
	NFS_CACHEINV(inode);
	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
	NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
}
/*
 * We judge how long we want to trust negative
 * dentries by looking at the parent inode mtime.
 *
 * If parent mtime has changed, we revalidate, else we wait for a
 * period corresponding to the parent's attribute cache timeout value.
 */
static inline int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry)
{
	if (!nfs_check_verifier(dir, dentry))
		return 1;
	return time_after(jiffies, dentry->d_time + NFS_ATTRTIMEO(dir));
}
int
nfs_permission(struct inode *inode, int mask)
{
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_access_cache *cache = &NFS_I(inode)->cache_access;
	struct rpc_cred *cred;
	int mode = inode->i_mode;
	int error;

	if (mask & MAY_WRITE) {
		/*
		 *
		 * Nobody gets write access to a read-only fs.
		 *
		 */
		if (IS_RDONLY(inode) &&
		    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
			return -EROFS;

		/*
		 *
		 * Nobody gets write access to an immutable file.
		 *
		 */
		if (IS_IMMUTABLE(inode))
			return -EACCES;
	}

	if ((server->flags & NFS_MOUNT_NOACL) || !NFS_PROTO(inode)->access)
		goto out_notsup;
	cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
	if (cache->cred == cred
	    && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))) {
		if (!cache->err) {
			/* Is the mask a subset of an accepted mask? */
			if ((cache->mask & mask) == mask)
				goto out_cached;
	       	} else {
			/* ...or is it a superset of a rejected mask? */
			if ((cache->mask & mask) == cache->mask)
				goto out_cached;
		}
	}
	error = NFS_PROTO(inode)->access(inode, cred, mask);
	if (!error || error == -EACCES) {
		cache->jiffies = jiffies;
		if (cache->cred)
			put_rpccred(cache->cred);
		cache->cred = cred;
		cache->mask = mask;
		cache->err = error;
		return error;
	}
	put_rpccred(cred);
out_notsup:
	nfs_revalidate_inode(NFS_SERVER(inode), inode);
	return vfs_permission(inode, mask);
out_cached:
	put_rpccred(cred);
	return cache->err;
}
Exemplo n.º 9
0
int
nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
{
	struct nfs_access_cache *cache = &NFS_I(inode)->cache_access;
	struct rpc_cred *cred;
	int mode = inode->i_mode;
	int res;

	if (mask == 0)
		return 0;
	if (mask & MAY_WRITE) {
		/*
		 *
		 * Nobody gets write access to a read-only fs.
		 *
		 */
		if (IS_RDONLY(inode) &&
		    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
			return -EROFS;

		/*
		 *
		 * Nobody gets write access to an immutable file.
		 *
		 */
		if (IS_IMMUTABLE(inode))
			return -EACCES;
	}
	/* Are we checking permissions on anything other than lookup/execute? */
	if ((mask & MAY_EXEC) == 0) {
		/* We only need to check permissions on file open() and access() */
		if (!nd || !(nd->flags & (LOOKUP_OPEN|LOOKUP_ACCESS)))
			return 0;
		/* NFSv4 has atomic_open... */
		if (NFS_PROTO(inode)->version > 3 && (nd->flags & LOOKUP_OPEN))
			return 0;
	}

	lock_kernel();

	if (!NFS_PROTO(inode)->access)
		goto out_notsup;

	cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
	if (cache->cred == cred
	    && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))
	    && !(NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR)) {
		if (!(res = cache->err)) {
			/* Is the mask a subset of an accepted mask? */
			if ((cache->mask & mask) == mask)
				goto out;
		} else {
			/* ...or is it a superset of a rejected mask? */
			if ((cache->mask & mask) == cache->mask)
				goto out;
		}
	}

	res = NFS_PROTO(inode)->access(inode, cred, mask);
	if (!res || res == -EACCES)
		goto add_cache;
out:
	put_rpccred(cred);
	unlock_kernel();
	return res;
out_notsup:
	nfs_revalidate_inode(NFS_SERVER(inode), inode);
	res = vfs_permission(inode, mask);
	unlock_kernel();
	return res;
add_cache:
	cache->jiffies = jiffies;
	if (cache->cred)
		put_rpccred(cache->cred);
	cache->cred = cred;
	cache->mask = mask;
	cache->err = res;
	unlock_kernel();
	return res;
}