Index: fs/Kconfig
===================================================================
RCS file: /cvs/l26/fs/Kconfig,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -c -p -c -3 -p -r1.1.1.2 -r1.3
*** fs/Kconfig	7 Apr 2004 07:34:50 -0000	1.1.1.2
--- fs/Kconfig	20 May 2004 19:15:50 -0000	1.3
*************** config AFS_FS
*** 1614,1619 ****
--- 1614,1640 ----
  config RXRPC
  	tristate
  
+ config ZFS_FS
+ 	tristate "ZFS support (Experimental)"
+ 	depends on INET && EXPERIMENTAL
+ 	help
+ 	  ZFS is an advanced network file system, similar to NFS in that it
+ 	  enables you to mount file systems of a remote server and access them
+ 	  with regular Unix commands as if they were sitting on your hard
+ 	  disk. ZFS has several advantages over NFS: support for
+ 	  disconnected operation (e.g. for laptops), persistent client caches
+ 	  and write back caching.
+ 
+ 	  If you say Y here, your Linux box will be able to act as a ZFS
+ 	  *client*. You will need user level daemon as well, both for the
+ 	  client and server. Servers are currently user level, i.e. they need
+ 	  no kernel support.
+ 
+ 	  To compile the ZFS client support as a module, choose M here: the
+ 	  module will be called zfs.
+ 
+ 	  If unsure, say N.
+ 
  endmenu
  
  menu "Partition Types"
Index: fs/Makefile
===================================================================
RCS file: /cvs/l26/fs/Makefile,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -c -p -c -3 -p -r1.1.1.2 -r1.2
*** fs/Makefile	7 Apr 2004 07:34:50 -0000	1.1.1.2
--- fs/Makefile	27 Apr 2004 11:03:07 -0000	1.2
*************** obj-$(CONFIG_JFS_FS)		+= jfs/
*** 92,94 ****
--- 92,95 ----
  obj-$(CONFIG_XFS_FS)		+= xfs/
  obj-$(CONFIG_AFS_FS)		+= afs/
  obj-$(CONFIG_BEFS_FS)		+= befs/
+ obj-$(CONFIG_ZFS_FS)		+= zfs/
Index: fs/zfs/.cvsignore
===================================================================
RCS file: fs/zfs/.cvsignore
diff -N fs/zfs/.cvsignore
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- fs/zfs/.cvsignore	15 May 2004 14:07:39 -0000	1.1
***************
*** 0 ****
--- 1,4 ----
+ .cvsignore
+ *.cmd
+ zfs.ko
+ zfs.mod.c
Index: fs/zfs/Makefile
===================================================================
RCS file: fs/zfs/Makefile
diff -N fs/zfs/Makefile
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- fs/zfs/Makefile	4 May 2004 13:54:43 -0000	1.3
***************
*** 0 ****
--- 1,10 ----
+ #
+ # Makefile for the Linux ZFS filesystem routines.
+ #
+ 
+ obj-$(CONFIG_ZFS_FS) += zfs.o
+ zfs-objs := chardev.o data-coding.o dir.o file.o inode.o super.o zfs_prot.o zfsd_call.o
+ 
+ # If you want debugging output, please uncomment the following line.
+ 
+ EXTRA_CFLAGS += -DDEBUG
Index: fs/zfs/chardev.c
===================================================================
RCS file: fs/zfs/chardev.c
diff -N fs/zfs/chardev.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- fs/zfs/chardev.c	28 May 2004 09:58:51 -0000	1.13
***************
*** 0 ****
--- 1,296 ----
+ /*
+    Chardev operations - communication channel between this kernel
+    module and ZFSd.
+    Copyright (C) 2004 Martin Zlomek
+ 
+    This file is part of ZFS.
+ 
+    ZFS is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+ 
+    ZFS is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+    License for more details.
+ 
+    You should have received a copy of the GNU General Public License along with
+    ZFS; see the file COPYING.  If not, write to the Free Software Foundation,
+    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA;
+    or download it from http://www.gnu.org/licenses/gpl.html
+  */
+ 
+ #include <linux/module.h>
+ #include <linux/fs.h>
+ #include <linux/list.h>
+ #include <linux/wait.h>
+ #include <linux/errno.h>
+ #include <linux/types.h>
+ #include <asm/semaphore.h>
+ #include <asm/uaccess.h>
+ 
+ #include "zfs.h"
+ #include "data-coding.h"
+ #include "zfs_prot.h"
+ 
+ 
+ static ssize_t zfs_chardev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *off)
+ {
+ 	struct request *req;
+ 
+ 	TRACE("%u: reading %u bytes (going to sleep if no data avaible)", current->pid, nbytes);
+ 
+ NEXT_REQUEST:
+ 	/* Wait for a request. */
+ 	down_interruptible(&channel.req_pending_count);
+ 
+ 	if (signal_pending(current)) {
+ 		TRACE("%u: interrupt", current->pid);
+ 		return -EINTR;
+ 	}
+ 	if (!channel.connected) {
+ 		TRACE("%u: zfsd closed communication device", current->pid);
+ 		return -EIO;
+ 	}
+ 
+ 	/* Remove the first request from the queue of pending requests if copy_to_user() succeeds. */
+ 	down(&channel.req_pending_lock);
+ 
+ 	req = list_entry(channel.req_pending.next, struct request, item);
+ 	if (down_trylock(&req->lock)) {
+ 		/* ZFS thread (running in send_request()) is being interrupted. */
+ 		up(&channel.req_pending_lock);
+ 		up(&channel.req_pending_count);
+ 		goto NEXT_REQUEST;
+ 	}
+ 
+   	if (req->length > nbytes) {
+ 		WARN("%u: reading only %u bytes of %u in message", current->pid, nbytes, req->length);
+ 		req->length = nbytes;
+ 	} else
+ 		nbytes = req->length;
+ 
+ 	if (copy_to_user(buf, req->dc->buffer, nbytes)) {
+ 		up(&channel.req_pending_lock);
+ 		up(&channel.req_pending_count);
+ 		return -EFAULT;
+ 	}
+ 
+ 	list_del(&req->item);
+ 
+ 	up(&channel.req_pending_lock);
+ 
+ 	/* Put the data coding buffer (DC), we do not need it any more. */
+ 	dc_put(req->dc);
+ 	req->dc = NULL;
+ 
+ 	/* Add the request to the queue of processing requests. We need this to be able to compare id of the request with id of the reply later. */
+ 	down(&channel.req_processing_lock);
+ 	list_add_tail(&req->item, &channel.req_processing[INDEX(req->id)]);
+ 	up(&channel.req_processing_lock);
+ 
+ 	req->state = REQ_PROCESSING;
+ 
+ 	up(&req->lock);
+ 
+ 	TRACE("%u: %u bytes read", current->pid, nbytes);
+ 
+ 	return nbytes;
+ }
+ 
+ extern struct inode *zfs_ilookup(struct super_block *sb, zfs_fh *fh);
+ 
+ static ssize_t zfs_chardev_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *off)
+ {
+ 	struct list_head *item;
+ 	struct request *req;
+ 	DC *dc;
+ 	direction dir;
+ 	unsigned int id;
+ 	int error = 0;
+ 
+ 	TRACE("%u: writting %u bytes", current->pid, nbytes);
+ 
+ 	if (nbytes > DC_SIZE) {
+ 		WARN("%u: zfsd has written %u bytes but max. %u is allowed in message", current->pid, nbytes, DC_SIZE);
+ 		return -EINVAL;
+ 	}
+ 
+ 	/* Get a new DC for the reply. */
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	if (copy_from_user(dc->buffer, buf, nbytes))
+ 		error = -EFAULT;
+ 	else if (!start_decoding(dc)
+ 		 || !decode_direction(dc, &dir)
+ 		 || !decode_request_id(dc, &id))
+ 		error = -EINVAL;
+ 	else
+ 		switch (dir) {
+ 			case DIR_REQUEST:
+ 				/* TODO: ZFSd wants something, we must send a reply with the same id. */
+ 				break;
+ 			case DIR_REPLY:
+ 				/* Find the request the reply belongs to. */
+ 				down(&channel.req_processing_lock);
+ 				list_for_each(item, &channel.req_processing[INDEX(id)]) {
+ 					req = list_entry(item, struct request, item);
+ 					if (down_trylock(&req->lock))
+ 						continue;
+ 					if (id == req->id) {
+ 						TRACE("%u: request corresponding to reply id %u found", current->pid, id);
+ 
+ 						/* Remove the request from the queue of processing requests. */
+ 						list_del(item);
+ 						up(&channel.req_processing_lock);
+ 
+ 						req->state = REQ_DEQUEUED;
+ 
+ 						/* Store the DC of the reply. */
+ 						req->dc = dc;
+ 
+ 						/* Wake up the thread which is waiting for the reply. */
+ 						wake_up(&req->waitq);
+ 
+ 						up(&req->lock);
+ 
+ 						return nbytes;
+ 					}
+ 					up(&req->lock);
+ 				}
+ 				up(&channel.req_processing_lock);
+ 
+ 				WARN("%u: no request corresponding to reply id %u found", current->pid, id);
+ 
+ 				break;
+ 			case DIR_ONEWAY:
+ 				{
+ 					uint32_t fn;
+ 
+ 					if (!decode_function(dc, &fn))
+ 						error = -EINVAL;
+ 					else
+ 						switch (fn) {
+ 							case ZFS_PROC_INVALIDATE:
+ 								if (!zfs_sb)
+ 									error = -EIO;
+ 								else {
+ 									invalidate_args args;
+ 
+ 									if (!decode_invalidate_args(dc, &args)
+ 									    || !finish_decoding(dc))
+ 										error = -EPROTO;
+ 									else {
+ 										struct inode *inode;
+ 
+ 										TRACE("%u: invalidate [sid: %u, vid: %u, dev: %u, ino: %u, gen: %u]", current->pid, args.fh.sid, args.fh.vid, args.fh.dev, args.fh.ino, args.fh.gen);
+ 
+ 										inode = zfs_ilookup(zfs_sb, &args.fh);
+ 										if (inode) {
+ 											TRACE("%u: %p invalidated", current->pid, inode);
+ 											make_bad_inode(inode);
+ 										} else
+ 											TRACE("%u: no inode invalidated", current->pid);
+ 									}
+ 								}
+ 								break;
+ 							default:
+ 								error = -EINVAL;
+ 								break;
+ 						}
+ 				}
+ 				break;
+ 			default:
+ 				break;
+ 		}
+ 
+ 	dc_put(dc);
+ 
+ 	if (error)
+ 		TRACE("%u: %d", current->pid, error);
+ 	else
+ 		TRACE("%u: %u bytes written", current->pid, nbytes);
+ 
+ 	return error ? error : nbytes;
+ }
+ 
+ static int zfs_chardev_open(struct inode *inode, struct file *file)
+ {
+ 	int i;
+ 
+ 	TRACE("%u", current->pid);
+ 
+ 	down(&channel.lock);
+ 
+ 	if (channel.connected) {
+ 		up(&channel.lock);
+ 		return -EBUSY;
+ 	}
+ 
+ 	init_MUTEX(&channel.request_id_lock);
+ 	channel.request_id = 0;
+ 
+ 	init_MUTEX_LOCKED(&channel.req_pending_count);
+ 
+ 	init_MUTEX(&channel.req_pending_lock);
+ 	INIT_LIST_HEAD(&channel.req_pending);
+ 
+ 	init_MUTEX(&channel.req_processing_lock);
+ 	for (i = 0; i < REQ_PROCESSING_TABSIZE; i++)
+ 		INIT_LIST_HEAD(&channel.req_processing[i]);
+ 
+ 	channel.connected = 1;
+ 
+ 	up(&channel.lock);
+ 
+ 	return 0;
+ }
+ 
+ static int zfs_chardev_release(struct inode *inode, struct file *file)
+ {
+ 	struct list_head *item;
+ 	struct request *req;
+ 	int i;
+ 
+ 	TRACE("%u", current->pid);
+ 
+ 	down(&channel.lock);
+ 
+ 	channel.connected = 0;
+ 
+ 	wake_up_all(&channel.req_pending_count.wait);
+ 	/* No up(&req_pending_count) is neccessary - the samaphore will be initialized in the next call of zfs_chardev_open(). */
+ 
+ 	down(&channel.req_pending_lock);
+ 	list_for_each(item, &channel.req_pending) {
+ 		req = list_entry(item, struct request, item);
+ 		wake_up(&req->waitq);
+ 	}
+ 	up(&channel.req_pending_lock);
+ 
+ 	down(&channel.req_processing_lock);
+ 	for (i = 0; i < REQ_PROCESSING_TABSIZE; i++)
+ 		list_for_each(item, &channel.req_processing[i]) {
+ 			req = list_entry(item, struct request, item);
+ 			wake_up(&req->waitq);
+ 		}
+ 	up(&channel.req_processing_lock);
+ 
+ 	up(&channel.lock);
+ 
+ 	/* Free all allocated DCs. */
+ 	dc_destroy_all();
+ 
+ 	return 0;
+ }
+ 
+ struct file_operations zfs_chardev_file_operations = {
+ 	.owner		= THIS_MODULE,
+ 	.read		= zfs_chardev_read,
+ 	.write		= zfs_chardev_write,
+ 	.open		= zfs_chardev_open,
+ 	.release	= zfs_chardev_release,
+ };
Index: fs/zfs/dir.c
===================================================================
RCS file: fs/zfs/dir.c
diff -N fs/zfs/dir.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- fs/zfs/dir.c	22 May 2004 11:22:33 -0000	1.8
***************
*** 0 ****
--- 1,61 ----
+ /*
+    Directory operations.
+    Copyright (C) 2004 Martin Zlomek
+ 
+    This file is part of ZFS.
+ 
+    ZFS is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+ 
+    ZFS is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+    License for more details.
+ 
+    You should have received a copy of the GNU General Public License along with
+    ZFS; see the file COPYING.  If not, write to the Free Software Foundation,
+    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA;
+    or download it from http://www.gnu.org/licenses/gpl.html
+  */
+ 
+ #include <linux/fs.h>
+ 
+ #include "zfs.h"
+ #include "zfs_prot.h"
+ #include "zfsd_call.h"
+ 
+ 
+ static int zfs_readdir(struct file *file, void *dirent, filldir_t filldir)
+ {
+ 	struct inode *inode = file->f_dentry->d_inode;
+ 	read_dir_args args;
+ 	int error;
+ 
+ 	TRACE("'%s'", file->f_dentry->d_name.name);
+ 
+ 	if (file->f_pos == -1)
+ 		return 0;
+ 
+ 	args.cap = *CAP(file->private_data);
+ 	args.cookie = file->f_pos ? *COOKIE(file->private_data) : 0;
+ 	args.count = ZFS_MAXDATA;
+ 
+ 	error = zfsd_readdir(&args, file, dirent, filldir);
+ 	if ((error == -ESTALE) && !IS_ROOT_INODE(inode))
+ 		make_bad_inode(inode);
+ 
+ 	return error;
+ }
+ 
+ extern int zfs_open(struct inode *inode, struct file *file);
+ extern int zfs_release(struct inode *inode, struct file *file);
+ 
+ struct file_operations zfs_dir_operations = {
+ 	.llseek         = generic_file_llseek,
+ 	.read           = generic_read_dir,
+ 	.readdir        = zfs_readdir,
+ 	.open           = zfs_open,
+ 	.release        = zfs_release,
+ };
Index: fs/zfs/file.c
===================================================================
RCS file: fs/zfs/file.c
diff -N fs/zfs/file.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- fs/zfs/file.c	22 May 2004 11:22:33 -0000	1.11
***************
*** 0 ****
--- 1,180 ----
+ /*
+    File operations.
+    Copyright (C) 2004 Martin Zlomek
+ 
+    This file is part of ZFS.
+ 
+    ZFS is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+ 
+    ZFS is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+    License for more details.
+ 
+    You should have received a copy of the GNU General Public License along with
+    ZFS; see the file COPYING.  If not, write to the Free Software Foundation,
+    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA;
+    or download it from http://www.gnu.org/licenses/gpl.html
+  */
+ 
+ #include <linux/fs.h>
+ #include <linux/slab.h>
+ #include <linux/errno.h>
+ #include <linux/time.h>
+ #include <linux/pagemap.h>
+ #include <linux/string.h>
+ 
+ #include "zfs.h"
+ #include "zfs_prot.h"
+ #include "zfsd_call.h"
+ 
+ 
+ static ssize_t zfs_read(struct file *file, char __user *buf, size_t nbytes, loff_t *off)
+ {
+ 	struct inode *inode = file->f_dentry->d_inode;
+ 	read_args args;
+ 	int error;
+ 
+ 	TRACE("'%s': %lld", file->f_dentry->d_name.name, *off);
+ 
+ 	args.cap = *CAP(file->private_data);
+ 	args.offset = *off;
+ 	args.count = (nbytes > ZFS_MAXDATA) ? ZFS_MAXDATA : nbytes;
+ 
+ 	error = zfsd_read(buf, &args);
+ 	if (error > 0) {
+ 		*off += error;
+ 		inode->i_atime = CURRENT_TIME;
+ 	} else if (error == -ESTALE)
+ 		make_bad_inode(inode);
+ 
+ 	return error;
+ }
+ 
+ static ssize_t zfs_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *off)
+ {
+ 	struct inode *inode = file->f_dentry->d_inode;
+ 	write_args args;
+ 	int error;
+ 
+ 	TRACE("'%s': %lld", file->f_dentry->d_name.name, *off);
+ 
+ 	args.cap = *CAP(file->private_data);
+ 	args.offset = *off;
+ 	args.data.len = (nbytes > ZFS_MAXDATA) ? ZFS_MAXDATA : nbytes;
+ 	args.data.buf = buf;
+ 
+ 	error = zfsd_write(&args);
+ 	if (error > 0) {
+ 		*off += error;
+ 		inode->i_mtime = CURRENT_TIME;
+ 		if (*off > inode->i_size) {
+ 			inode->i_size = *off;
+ 			inode->i_ctime = CURRENT_TIME;
+ 		}
+ 	} else if (error == -ESTALE)
+ 		make_bad_inode(inode);
+ 
+ 	return error;
+ }
+ 
+ int zfs_open(struct inode *inode, struct file *file)
+ {
+ 	struct dentry *dentry = file->f_dentry;
+ 	zfs_cap *cap;
+ 	open_args args;
+ 	int error;
+ 
+ 	TRACE("'%s'", dentry->d_name.name);
+ 
+ 	if ((file->f_flags & O_CREAT) && dentry->d_fsdata) {
+ 		/* We already have CAP for the file (zfs_create() has found it out). */
+ 		file->private_data = dentry->d_fsdata;
+ 		dentry->d_fsdata = NULL;
+ 	} else {
+ 		cap = kmalloc(sizeof(zfs_cap) + (S_ISDIR(inode->i_mode) ? sizeof(int32_t) : 0), GFP_KERNEL);
+ 		if (!cap)
+ 			return -ENOMEM;
+ 
+ 		args.file = ZFS_I(inode)->fh;
+ 		args.flags = file->f_flags;
+ 
+ 		error = zfsd_open(cap, &args);
+ 		if (error) {
+ 			kfree(cap);
+ 			if ((error == -ESTALE) && !IS_ROOT_INODE(inode))
+ 				make_bad_inode(inode);
+ 			return error;
+ 		}
+ 
+ 		file->private_data = cap;
+ 	}
+ 
+ 	return 0;
+ }
+ 
+ int zfs_release(struct inode *inode, struct file *file)
+ {
+ 	int error;
+ 
+ 	TRACE("'%s'", file->f_dentry->d_name.name);
+ 
+ 	error = zfsd_close(CAP(file->private_data));
+ 
+ 	kfree(file->private_data);
+ 
+ 	return error;
+ }
+ 
+ static int zfs_readpage(struct file *file, struct page *page)
+ {
+ 	char *kaddr;
+ 	read_args args;
+ 	int error = 0;
+ 
+ 	TRACE("'%s': %lu", file->f_dentry->d_name.name, page->index);
+ 
+ 	if (PageUptodate(page))
+ 		goto out;
+ 
+ 	args.cap = *CAP(file->private_data);
+ 	args.offset = page->index << PAGE_CACHE_SHIFT;
+ 	args.count = PAGE_CACHE_SIZE;
+ 
+ 	kaddr = kmap(page);
+ 
+ 	error = zfsd_readpage(kaddr, &args);
+ 	if (error > 0) {
+ 		if (error < PAGE_CACHE_SIZE)
+ 			/* Zero the rest of the page. */
+ 			memset(kaddr + error, 0, PAGE_CACHE_SIZE - error);
+ 
+ 		SetPageUptodate(page);
+ 
+ 		error = 0;
+ 	} else if (error == -ESTALE)
+ 		make_bad_inode(file->f_dentry->d_inode);
+ 
+ 	kunmap(kaddr);
+ 
+ out:
+ 	unlock_page(page);
+ 
+ 	return error;
+ }
+ 
+ struct file_operations zfs_file_operations = {
+ 	.llseek         = generic_file_llseek,
+ 	.read           = zfs_read,
+ 	.write          = zfs_write,
+ 	.mmap		= generic_file_readonly_mmap,
+ 	.open           = zfs_open,
+ 	.release        = zfs_release,
+ };
+ 
+ struct address_space_operations zfs_file_address_space_operations = {
+ 	.readpage           = zfs_readpage,
+ };
Index: fs/zfs/inode.c
===================================================================
RCS file: fs/zfs/inode.c
diff -N fs/zfs/inode.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- fs/zfs/inode.c	27 May 2004 19:30:36 -0000	1.19
***************
*** 0 ****
--- 1,601 ----
+ /*
+    Inode operations.
+    Copyright (C) 2004 Martin Zlomek
+ 
+    This file is part of ZFS.
+ 
+    ZFS is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+ 
+    ZFS is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+    License for more details.
+ 
+    You should have received a copy of the GNU General Public License along with
+    ZFS; see the file COPYING.  If not, write to the Free Software Foundation,
+    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA;
+    or download it from http://www.gnu.org/licenses/gpl.html
+  */
+ 
+ #include <linux/fs.h>
+ #include <linux/errno.h>
+ #include <linux/string.h>
+ #include <linux/stat.h>
+ #include <linux/namei.h>
+ #include <linux/sched.h>
+ #include <linux/time.h>
+ 
+ #include "zfs.h"
+ #include "zfs_prot.h"
+ #include "zfsd_call.h"
+ 
+ 
+ static void zfs_iattr_to_sattr(sattr *attr, struct iattr *iattr)
+ {
+ 	unsigned int valid = iattr->ia_valid;
+ 
+ 	attr->mode = (valid & ATTR_MODE) ? (iattr->ia_mode & S_IALLUGO) : -1;
+ 	attr->uid = (valid & ATTR_UID) ? iattr->ia_uid : -1;
+ 	attr->gid = (valid & ATTR_GID) ? iattr->ia_gid : -1;
+ 	attr->size = (valid & ATTR_SIZE) ? iattr->ia_size : -1;
+ 	attr->atime = (valid & ATTR_ATIME) ? iattr->ia_atime.tv_sec : -1;
+ 	attr->mtime = (valid & ATTR_MTIME) ? iattr->ia_mtime.tv_sec : -1;
+ }
+ 
+ static void zfs_attr_to_iattr(struct inode *inode, fattr *attr)
+ {
+ 	inode->i_ino = attr->ino;
+ 	inode->i_version = attr->version;
+ 	inode->i_mode = ftype2mode[attr->type] | attr->mode;
+ 	inode->i_nlink = attr->nlink;
+ 	inode->i_uid = attr->uid;
+ 	inode->i_gid = attr->gid;
+ 	inode->i_rdev = attr->rdev;
+ 	inode->i_size = attr->size;
+ 	inode->i_blocks = attr->blocks;
+ 	inode->i_blksize = attr->blksize;
+ 	inode->i_atime.tv_sec = attr->atime;
+ 	inode->i_atime.tv_nsec = 0;
+ 	inode->i_mtime.tv_sec = attr->mtime;
+ 	inode->i_mtime.tv_nsec = 0;
+ 	inode->i_ctime.tv_sec = attr->ctime;
+ 	inode->i_ctime.tv_nsec = 0;
+ }
+ 
+ static ftype zfs_mode_to_ftype(int mode)
+ {
+ 	switch (mode & S_IFMT) {
+ 		case S_IFSOCK:
+ 			return FT_SOCK;
+ 		case S_IFLNK:
+ 			return FT_LNK;
+ 		case S_IFREG:
+ 			return FT_REG;
+ 		case S_IFBLK:
+ 			return FT_BLK;
+ 		case S_IFDIR:
+ 			return FT_DIR;
+ 		case S_IFCHR:
+ 			return FT_CHR;
+ 		case S_IFIFO:
+ 			return FT_FIFO;
+ 		default:
+ 			return FT_BAD;
+ 	}
+ }
+ 
+ static struct inode_operations zfs_dir_inode_operations, zfs_file_inode_operations, zfs_symlink_inode_operations;
+ extern struct file_operations zfs_dir_operations, zfs_file_operations;
+ extern struct address_space_operations zfs_file_address_space_operations;
+ 
+ static void zfs_fill_inode(struct inode *inode, fattr *attr)
+ {
+ 	zfs_attr_to_iattr(inode, attr);
+ 	switch (inode->i_mode & S_IFMT) {
+ 		case S_IFREG:
+ 			inode->i_op = &zfs_file_inode_operations;
+ 			inode->i_fop = &zfs_file_operations;
+ 			inode->i_data.a_ops = &zfs_file_address_space_operations;
+ 			break;
+ 		case S_IFDIR:
+ 			inode->i_op = &zfs_dir_inode_operations;
+ 			inode->i_fop = &zfs_dir_operations;
+ 			break;
+ 		case S_IFLNK:
+ 			inode->i_op = &zfs_symlink_inode_operations;
+ 			break;
+ 		default:
+ 			init_special_inode(inode, inode->i_mode, huge_decode_dev(inode->i_rdev));
+ 			break;
+ 	}
+ }
+ 
+ static int zfs_test_inode(struct inode *inode, void *data)
+ {
+ 	return !memcmp(&ZFS_I(inode)->fh, data, sizeof(zfs_fh));
+ }
+ 
+ static int zfs_set_inode(struct inode *inode, void *data)
+ {
+ 	ZFS_I(inode)->fh = *(zfs_fh *)data;
+ 
+ 	return 0;
+ }
+ 
+ struct inode *zfs_ilookup(struct super_block *sb, zfs_fh *fh)
+ {
+ 	return ilookup5(sb, HASH(fh), zfs_test_inode, fh);
+ }
+ 
+ struct inode *zfs_iget(struct super_block *sb, zfs_fh *fh, fattr *attr)
+ {
+ 	struct inode *inode;
+ 
+ 	TRACE("%u", fh->ino);
+ 
+ 	inode = iget5_locked(sb, HASH(fh), zfs_test_inode, zfs_set_inode, fh);
+ 
+ 	if (inode && (inode->i_state & I_NEW)) {
+ 		zfs_fill_inode(inode, attr);
+ 		unlock_new_inode(inode);
+ 	}
+ 
+ 	return inode;
+ }
+ 
+ static int zfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+ {
+ 	struct inode *inode = dentry->d_inode;
+ 	fattr attr;
+ 
+ 	TRACE("'%s'", dentry->d_name.name);
+ 
+ 	if (!inode)
+ 		return 1;
+ 
+ 	if (is_bad_inode(inode))
+ 		return 0;
+ 
+ 	if (time_after(jiffies, dentry->d_time + ZFS_DENTRY_MAXAGE * HZ)) {
+ 		/* The dentry is too old, so revalidate it. */
+ 		if (zfsd_getattr(&attr, &ZFS_I(inode)->fh)
+ 		    || (attr.version != inode->i_version)) {
+ 			make_bad_inode(dentry->d_inode);
+ 			return 0;
+ 		}
+ 
+ 		zfs_attr_to_iattr(inode, &attr);
+ 		dentry->d_time = jiffies;
+ 	}
+ 
+ 	return 1;
+ }
+ 
+ struct dentry_operations zfs_dentry_operations = {
+ 	.d_revalidate   = zfs_d_revalidate,
+ };
+ 
+ static int zfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
+ {
+ 	create_args args;
+ 	create_res res;
+ 	struct inode *inode;
+ 	int error;
+ 
+ 	TRACE("'%s'", dentry->d_name.name);
+ 
+ 	args.where.dir = ZFS_I(dir)->fh;
+ 	args.where.name.str = (char *)dentry->d_name.name;
+ 	args.where.name.len = dentry->d_name.len;
+ 	args.flags = nd->intent.open.flags;
+ 	if (args.flags & O_ACCMODE)
+ 		args.flags--;
+ 	args.attr.mode = mode & S_IALLUGO;
+ 	args.attr.uid = current->fsuid;
+ 	if (dir->i_mode & S_ISGID)
+ 		args.attr.gid = dir->i_gid;
+ 	else
+ 		args.attr.gid = current->fsgid;
+ 	args.attr.size = -1;
+ 	args.attr.atime = -1;
+ 	args.attr.mtime = -1;
+ 
+ 	error = zfsd_create(&res, &args);
+ 	if (error) {
+ 		if ((error == -ESTALE) && !IS_ROOT_INODE(dir))
+ 			make_bad_inode(dir);
+ 		return error;
+ 	}
+ 
+ 	inode = zfs_iget(dir->i_sb, &res.file, &res.attr);
+ 	if (!inode)
+ 		return -ENOMEM;
+ 
+ 	dentry->d_fsdata = kmalloc(sizeof(zfs_cap), GFP_KERNEL);
+ 	if (!dentry->d_fsdata)
+ 		return -ENOMEM;
+ 	*(zfs_cap *)dentry->d_fsdata = res.cap;
+ 
+ 	d_instantiate(dentry, inode);
+ 
+ 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ 
+ 	return 0;
+ }
+ 
+ static struct dentry *zfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+ {
+ 	dir_op_args args;
+ 	dir_op_res res;
+ 	struct inode *inode;
+ 	int error;
+ 
+ 	TRACE("'%s'", dentry->d_name.name);
+ 
+ 	if (dentry->d_name.len > ZFS_MAXNAMELEN)
+ 		return ERR_PTR(-ENAMETOOLONG);
+ 
+ 	args.dir = ZFS_I(dir)->fh;
+ 	args.name.str = (char *)dentry->d_name.name;
+ 	args.name.len = dentry->d_name.len;
+ 
+ 	error = zfsd_lookup(&res, &args);
+ 	if (!error) {
+ 		inode = zfs_iget(dir->i_sb, &res.file, &res.attr);
+ 		if (!inode)
+ 			return ERR_PTR(-ENOMEM);
+ 	} else if (error != -ENOENT) {
+ 		if ((error == -ESTALE) && !IS_ROOT_INODE(dir))
+ 			make_bad_inode(dir);
+ 		return ERR_PTR(error);
+ 	} else
+ 		inode = NULL;
+ 
+ 	dentry->d_time = jiffies;
+ 	dentry->d_op = &zfs_dentry_operations;
+ 
+ 	d_add(dentry, inode);
+ 
+ 	return NULL;
+ }
+ 
+ static int zfs_link(struct dentry *src_dentry, struct inode *dir, struct dentry *dentry)
+ {
+ 	struct inode *inode = src_dentry->d_inode;
+ 	link_args args;
+ 	int error;
+ 
+ 	TRACE("'%s' -> '%s'", dentry->d_name.name, src_dentry->d_name.name);
+ 
+ 	args.from = ZFS_I(inode)->fh;
+ 	args.to.dir = ZFS_I(dir)->fh;
+ 	args.to.name.str = (char *)dentry->d_name.name;
+ 	args.to.name.len = dentry->d_name.len;
+ 
+ 	error = zfsd_link(&args);
+ 	if (error) {
+ 		if (error == -ESTALE) {
+ 			/* We do not know which one (dir or inode) is bad, so invalidate both. */
+ 			if (!IS_ROOT_INODE(dir))
+ 				make_bad_inode(dir);
+ 			if (!IS_ROOT_INODE(inode))
+ 				make_bad_inode(inode);
+ 		}
+ 		return error;
+ 	}
+ 
+ 	inode->i_nlink++;
+ 	inode->i_ctime = CURRENT_TIME;
+ 
+ 	atomic_inc(&inode->i_count);
+ 	d_instantiate(dentry, inode);
+ 
+ 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ 
+ 	return 0;
+ }
+ 
+ static int zfs_unlink(struct inode *dir, struct dentry *dentry)
+ {
+ 	struct inode *inode = dentry->d_inode;
+ 	dir_op_args args;
+ 	int error;
+ 
+ 	TRACE("'%s'", dentry->d_name.name);
+ 
+ 	args.dir = ZFS_I(dir)->fh;
+ 	args.name.str = (char *)dentry->d_name.name;
+ 	args.name.len = dentry->d_name.len;
+ 
+ 	error = zfsd_unlink(&args);
+ 	if (error) {
+ 		if ((error == -ESTALE) && !IS_ROOT_INODE(dir))
+ 			make_bad_inode(dir);
+ 		return error;
+ 	}
+ 
+ 	inode->i_nlink--;
+ 	inode->i_ctime = CURRENT_TIME;
+ 
+ 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ 
+ 	return 0;
+ }
+ 
+ static int zfs_symlink(struct inode *dir, struct dentry *dentry, const char *old_name)
+ {
+ 	symlink_args args;
+ 	dir_op_res res;
+ 	struct inode *inode;
+ 	int error;
+ 
+ 	TRACE("'%s' -> '%s'", dentry->d_name.name, old_name);
+ 
+ 	if (strlen(old_name) > ZFS_MAXPATHLEN)
+ 		return -ENAMETOOLONG;
+ 
+ 	args.from.dir = ZFS_I(dir)->fh;
+ 	args.from.name.str = (char *)dentry->d_name.name;
+ 	args.from.name.len = dentry->d_name.len;
+ 	args.to.str = (char *)old_name;
+ 	args.to.len = strlen(old_name);
+ 	args.attr.mode = -1;
+ 	args.attr.uid = current->fsuid;
+ 	if (dir->i_mode & S_ISGID)
+ 		args.attr.gid = dir->i_gid;
+ 	else
+ 		args.attr.gid = current->fsgid;
+ 	args.attr.size = -1;
+ 	args.attr.atime = -1;
+ 	args.attr.mtime = -1;
+ 
+ 	error = zfsd_symlink(&res, &args);
+ 	if (error) {
+ 		if ((error == -ESTALE) && !IS_ROOT_INODE(dir))
+ 			make_bad_inode(dir);
+ 		return error;
+ 	}
+ 
+ 	inode = zfs_iget(dir->i_sb, &res.file, &res.attr);
+ 	if (!inode)
+ 		return -ENOMEM;
+ 
+ 	d_instantiate(dentry, inode);
+ 
+ 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ 
+ 	return 0;
+ }
+ 
+ static int zfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+ {
+ 	mkdir_args args;
+ 	dir_op_res res;
+ 	struct inode *inode;
+ 	int error;
+ 
+ 	TRACE("'%s'", dentry->d_name.name);
+ 
+ 	args.where.dir = ZFS_I(dir)->fh;
+ 	args.where.name.str = (char *)dentry->d_name.name;
+ 	args.where.name.len = dentry->d_name.len;
+ 	args.attr.mode = mode & (S_IRWXUGO | S_ISVTX);
+ 	args.attr.uid = current->fsuid;
+ 	if (dir->i_mode & S_ISGID) {
+ 		args.attr.gid = dir->i_gid;
+ 		args.attr.mode |= S_ISGID;
+ 	} else
+ 		args.attr.gid = current->fsgid;
+ 	args.attr.size = -1;
+ 	args.attr.atime = -1;
+ 	args.attr.mtime = -1;
+ 
+ 	error = zfsd_mkdir(&res, &args);
+ 	if (error) {
+ 		if ((error == -ESTALE) && !IS_ROOT_INODE(dir))
+ 			make_bad_inode(dir);
+ 		return error;
+ 	}
+ 
+ 	inode = zfs_iget(dir->i_sb, &res.file, &res.attr);
+ 	if (!inode)
+ 		return -ENOMEM;
+ 
+ 	d_instantiate(dentry, inode);
+ 
+ 	dir->i_nlink++;
+ 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ 
+ 	return 0;
+ }
+ 
+ static int zfs_rmdir(struct inode *dir, struct dentry *dentry)
+ {
+ 	struct inode *inode = dentry->d_inode;
+ 	dir_op_args args;
+ 	int error;
+ 
+ 	TRACE("'%s'", dentry->d_name.name);
+ 
+ 	args.dir = ZFS_I(dir)->fh;
+ 	args.name.str = (char *)dentry->d_name.name;
+ 	args.name.len = dentry->d_name.len;
+ 
+ 	error = zfsd_rmdir(&args);
+ 	if (error) {
+ 		if ((error == -ESTALE) && !IS_ROOT_INODE(dir))
+ 			make_bad_inode(dir);
+ 		return error;
+ 	}
+ 
+ 	inode->i_nlink--;
+ 
+ 	dir->i_nlink--;
+ 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ 
+ 	return 0;
+ }
+ 
+ static int zfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
+ {
+ 	mknod_args args;
+ 	dir_op_res res;
+ 	struct inode *inode;
+ 	int error;
+ 
+ 	TRACE("'%s'", dentry->d_name.name);
+ 
+ 	args.where.dir = ZFS_I(dir)->fh;
+ 	args.where.name.str = (char *)dentry->d_name.name;
+ 	args.where.name.len = dentry->d_name.len;
+ 	args.attr.mode = mode & S_IALLUGO;
+ 	args.attr.uid = current->fsuid;
+ 	if (dir->i_mode & S_ISGID)
+ 		args.attr.gid = dir->i_gid;
+ 	else
+ 		args.attr.gid = current->fsgid;
+ 	args.attr.size = -1;
+ 	args.attr.atime = -1;
+ 	args.attr.mtime = -1;
+ 	args.type = zfs_mode_to_ftype(mode);
+ 	args.rdev = huge_encode_dev(rdev);
+ 
+ 	error = zfsd_mknod(&res, &args);
+ 	if (error) {
+ 		if ((error == -ESTALE) && !IS_ROOT_INODE(dir))
+ 			make_bad_inode(dir);
+ 		return error;
+ 	}
+ 
+ 	inode = zfs_iget(dir->i_sb, &res.file, &res.attr);
+ 	if (!inode)
+ 		return -ENOMEM;
+ 
+ 	d_instantiate(dentry, inode);
+ 
+ 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+ 
+ 	return 0;
+ }
+ 
+ static int zfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry)
+ {
+ 	struct inode *old_inode = old_dentry->d_inode;
+ 	rename_args args;
+ 	int error;
+ 
+ 	TRACE("'%s' -> '%s'", old_dentry->d_name.name, new_dentry->d_name.name);
+ 
+ 	args.from.dir = ZFS_I(old_dir)->fh;
+ 	args.from.name.str = (char *)old_dentry->d_name.name;
+ 	args.from.name.len = old_dentry->d_name.len;
+ 	args.to.dir = ZFS_I(new_dir)->fh;
+ 	args.to.name.str = (char *)new_dentry->d_name.name;
+ 	args.to.name.len = new_dentry->d_name.len;
+ 
+ 	error = zfsd_rename(&args);
+ 	if (error) {
+ 		if (error == -ESTALE) {
+ 			if (!IS_ROOT_INODE(old_dir))
+ 				make_bad_inode(old_dir);
+ 			if (!IS_ROOT_INODE(new_dir))
+ 				make_bad_inode(new_dir);
+ 		}
+ 		return error;
+ 	}
+ 
+ 	if (S_ISDIR(old_inode->i_mode)) {
+ 		old_dir->i_nlink--;
+ 		new_dir->i_nlink++;
+ 	}
+ 	old_dir->i_mtime = old_dir->i_ctime = CURRENT_TIME;
+ 	new_dir->i_mtime = new_dir->i_ctime = CURRENT_TIME;
+ 
+ 	return 0;
+ }
+ 
+ static int zfs_setattr(struct dentry *dentry, struct iattr *iattr)
+ {
+ 	struct inode *inode = dentry->d_inode;
+ 	fattr attr;
+ 	sattr_args args;
+ 	int error;
+ 
+ 	TRACE("'%s'", dentry->d_name.name);
+ 
+ 	args.file = ZFS_I(inode)->fh;
+ 	zfs_iattr_to_sattr(&args.attr, iattr);
+ 
+ 	error = zfsd_setattr(&attr, &args);
+ 	if (error) {
+ 		if ((error == -ESTALE) && !IS_ROOT_INODE(inode))
+ 			make_bad_inode(inode);
+ 		return error;
+ 	}
+ 
+ 	zfs_attr_to_iattr(inode, &attr);
+ 
+ 	return 0;
+ }
+ 
+ static int zfs_readlink(struct dentry *dentry, char __user *buf, int buflen)
+ {
+ 	struct inode *inode = dentry->d_inode;
+ 	read_link_res res;
+ 	int error;
+ 
+ 	TRACE("'%s'", dentry->d_name.name);
+ 
+ 	error = zfsd_readlink(&res, &ZFS_I(inode)->fh);
+ 	if (error) {
+ 		if (error == -ESTALE)
+ 			make_bad_inode(inode);
+ 		return error;
+ 	}
+ 
+ 	return vfs_readlink(dentry, buf, buflen, res.path.str);
+ }
+ 
+ static int zfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+ {
+ 	struct inode *inode = dentry->d_inode;
+ 	read_link_res res;
+ 	int error;
+ 
+ 	TRACE("'%s'", dentry->d_name.name);
+ 
+ 	error = zfsd_readlink(&res, &ZFS_I(inode)->fh);
+ 	if (error) {
+ 		if (error == -ESTALE)
+ 			make_bad_inode(inode);
+ 		return error;
+ 	}
+ 
+ 	return vfs_follow_link(nd, res.path.str);
+ }
+ 
+ static struct inode_operations zfs_dir_inode_operations = {
+ 	.create         = zfs_create,
+ 	.lookup         = zfs_lookup,
+ 	.link           = zfs_link,
+ 	.unlink         = zfs_unlink,
+ 	.symlink        = zfs_symlink,
+ 	.mkdir          = zfs_mkdir,
+ 	.rmdir          = zfs_rmdir,
+ 	.mknod          = zfs_mknod,
+ 	.rename         = zfs_rename,
+ 	.setattr        = zfs_setattr,
+ };
+ 
+ static struct inode_operations zfs_file_inode_operations = {
+ 	.setattr        = zfs_setattr,
+ };
+ 
+ static struct inode_operations zfs_symlink_inode_operations = {
+ 	.readlink       = zfs_readlink,
+ 	.follow_link    = zfs_follow_link,
+ 	.setattr        = zfs_setattr,
+ };
Index: fs/zfs/super.c
===================================================================
RCS file: fs/zfs/super.c
diff -N fs/zfs/super.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- fs/zfs/super.c	27 May 2004 19:30:36 -0000	1.11
***************
*** 0 ****
--- 1,220 ----
+ /*
+    Superblock operations.
+    Copyright (C) 2004 Martin Zlomek
+ 
+    This file is part of ZFS.
+ 
+    ZFS is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+ 
+    ZFS is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+    License for more details.
+ 
+    You should have received a copy of the GNU General Public License along with
+    ZFS; see the file COPYING.  If not, write to the Free Software Foundation,
+    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA;
+    or download it from http://www.gnu.org/licenses/gpl.html
+  */
+ 
+ #include <linux/init.h>
+ #include <linux/module.h>
+ #include <linux/device.h>
+ #include <linux/fs.h>
+ #include <linux/statfs.h>
+ #include <linux/slab.h>
+ #include <linux/errno.h>
+ #include <asm/semaphore.h>
+ 
+ #include "zfs.h"
+ #include "zfs_prot.h"
+ #include "zfsd_call.h"
+ 
+ 
+ MODULE_LICENSE("GPL");
+ MODULE_ALIAS_CHARDEV_MAJOR(ZFS_CHARDEV_MAJOR);
+ 
+ struct super_block *zfs_sb;
+ struct channel channel;
+ 
+ extern struct file_operations zfs_chardev_file_operations;
+ 
+ static kmem_cache_t *zfs_inode_cachep;
+ 
+ static struct inode *zfs_alloc_inode(struct super_block *sb)
+ {
+ 	struct zfs_inode_info *ei;
+ 
+ 	ei = kmem_cache_alloc(zfs_inode_cachep, SLAB_KERNEL);
+ 	if (!ei)
+ 		return NULL;
+ 
+ 	TRACE("%p", &ei->vfs_inode);
+ 
+ 	return &ei->vfs_inode;
+ }
+ 
+ static void zfs_destroy_inode(struct inode *inode)
+ {
+ 	TRACE("%p", inode);
+ 
+ 	kmem_cache_free(zfs_inode_cachep, ZFS_I(inode));
+ }
+ 
+ static void zfs_init_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
+ {
+ 	struct zfs_inode_info *ei = (struct zfs_inode_info *)foo;
+ 
+ 	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR)
+ 		inode_init_once(&ei->vfs_inode);
+ }
+ 
+ static int zfs_init_inodecache(void)
+ {
+ 	zfs_inode_cachep = kmem_cache_create("zfs_inode_cache",
+ 					     sizeof(struct zfs_inode_info),
+ 					     0,
+ 					     SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT,
+ 					     zfs_init_once,
+ 					     NULL);
+ 	if (!zfs_inode_cachep)
+ 		return -ENOMEM;
+ 
+ 	return 0;
+ }
+ 
+ static void zfs_destroy_inodecache(void)
+ {
+ 	if (kmem_cache_destroy(zfs_inode_cachep))
+ 		INFO("zfs_inode_cache: not all structures were freed");
+ }
+ 
+ static void zfs_put_super(struct super_block *sb)
+ {
+ 	INFO("UMOUNT");
+ 
+ 	zfs_sb = NULL;
+ }
+ 
+ static int zfs_statfs(struct super_block *sb, struct kstatfs *buf)
+ {
+ 	buf->f_type = ZFS_SUPER_MAGIC;
+ 	buf->f_bsize = ZFS_MAXDATA;
+ 	buf->f_namelen = ZFS_MAXNAMELEN;
+ 
+ 	return 0;
+ }
+ 
+ static struct super_operations zfs_super_operations = {
+ 	.alloc_inode    = zfs_alloc_inode,
+ 	.destroy_inode  = zfs_destroy_inode,
+ 	.put_super	= zfs_put_super,
+ 	.statfs		= zfs_statfs,
+ };
+ 
+ extern struct inode *zfs_iget(struct super_block *sb, zfs_fh *fh, fattr *attr);
+ 
+ static int zfs_fill_super(struct super_block *sb, void *data, int silent)
+ {
+ 	zfs_fh root_fh;
+ 	fattr root_attr;
+ 	struct inode *root_inode;
+ 	int error;
+ 
+ 	INFO("MOUNT");
+ 
+ 	if (!channel.connected) {
+ 		ERROR("zfsd has not opened communication device!");
+ 		return -EIO;
+ 	}
+ 
+ 	sb->s_op = &zfs_super_operations;
+ 	sb->s_magic = ZFS_SUPER_MAGIC;
+ 
+ 	/* Get root file handle. */
+ 	error = zfsd_root(&root_fh);
+ 	if (error)
+ 		return error;
+ 
+ 	/* Get root inode attributes. */
+ 	error = zfsd_getattr(&root_attr, &root_fh);
+ 	if (error)
+ 		return error;
+ 
+ 	/* Make root inode. */
+ 	root_inode = zfs_iget(sb, &root_fh, &root_attr);
+ 	if (!root_inode)
+ 		return -ENOMEM;
+ 
+ 	/* Create root dentry. */
+ 	sb->s_root = d_alloc_root(root_inode);
+ 	if (!sb->s_root)
+ 		return -ENOMEM;
+ 
+ 	zfs_sb = sb;
+ 
+ 	return 0;
+ }
+ 
+ static struct super_block *zfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data)
+ {
+ 	return get_sb_single(fs_type, flags, data, zfs_fill_super);
+ }
+ 
+ static struct file_system_type zfs_type = {
+ 	.owner		= THIS_MODULE,
+ 	.name		= "zfs",
+ 	.get_sb		= zfs_get_sb,
+ 	.kill_sb	= kill_anon_super,
+ 	.fs_flags	= 0,
+ };
+ 
+ static int __init zfs_init(void)
+ {
+ 	int error;
+ 
+ 	INFO("INIT");
+ 
+ 	/* Register communication device. */
+ 	error = register_chrdev(ZFS_CHARDEV_MAJOR, "zfs", &zfs_chardev_file_operations);
+ 	if (error) {
+ 		ERROR("unable to register chardev major %d!", ZFS_CHARDEV_MAJOR);
+ 		return error;
+ 	}
+ 
+ 	/* Initialize inode cache. */
+ 	error = zfs_init_inodecache();
+ 	if (error) {
+ 		unregister_chrdev(ZFS_CHARDEV_MAJOR, "zfs");
+ 		ERROR("unable to create zfs inode cache!");
+ 		return error;
+ 	}
+ 
+ 	/* Register ZFS file system. */
+ 	error = register_filesystem(&zfs_type);
+ 	if (error) {
+ 		zfs_destroy_inodecache();
+ 		unregister_chrdev(ZFS_CHARDEV_MAJOR, "zfs");
+ 		ERROR("unable to register filesystem!");
+ 		return error;
+ 	}
+ 
+ 	init_MUTEX(&channel.lock);
+ 
+ 	return 0;
+ }
+ 
+ static void __exit zfs_exit(void)
+ {
+ 	INFO("EXIT");
+ 
+ 	unregister_filesystem(&zfs_type);
+ 	zfs_destroy_inodecache();
+ 	unregister_chrdev(ZFS_CHARDEV_MAJOR, "zfs");
+ }
+ 
+ module_init(zfs_init);
+ module_exit(zfs_exit);
Index: fs/zfs/zfs.h
===================================================================
RCS file: fs/zfs/zfs.h
diff -N fs/zfs/zfs.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- fs/zfs/zfs.h	27 May 2004 19:30:36 -0000	1.13
***************
*** 0 ****
--- 1,119 ----
+ /*
+    Module definitions.
+    Copyright (C) 2004 Martin Zlomek
+ 
+    This file is part of ZFS.
+ 
+    ZFS is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+ 
+    ZFS is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+    License for more details.
+ 
+    You should have received a copy of the GNU General Public License along with
+    ZFS; see the file COPYING.  If not, write to the Free Software Foundation,
+    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA;
+    or download it from http://www.gnu.org/licenses/gpl.html
+  */
+ 
+ #ifndef _ZFS_H
+ #define _ZFS_H
+ 
+ #include <linux/kernel.h>
+ #include <linux/fs.h>
+ #include <linux/list.h>
+ #include <linux/wait.h>
+ #include <asm/semaphore.h>
+ 
+ #include "constant.h"
+ #include "data-coding.h"
+ #include "zfs_prot.h"
+ 
+ 
+ #define ERROR(format, ...) printk(KERN_ERR "zfs: " format "\n", ##__VA_ARGS__)
+ #define WARN(format, ...) printk(KERN_WARNING "zfs: " format "\n", ##__VA_ARGS__)
+ #define INFO(format, ...) printk(KERN_INFO "zfs: " format "\n", ##__VA_ARGS__)
+ 
+ #ifdef DEBUG
+ # define TRACE(format, ...) printk(KERN_INFO "zfs: %s(): " format "\n", __func__, ##__VA_ARGS__)
+ #else
+ # define TRACE(...)
+ #endif
+ 
+ #define ZFS_SUPER_MAGIC *((uint32_t *)"zfs")
+ #define ZFS_CHARDEV_MAJOR 251
+ 
+ /* Timeout in seconds for request. */
+ #define ZFS_TIMEOUT (REQUEST_TIMEOUT + 5)
+ 
+ /* Maximum age of dentry in seconds after that revalidation is requered. */
+ #define ZFS_DENTRY_MAXAGE 10
+ 
+ /* Is INODE root inode? */
+ #define IS_ROOT_INODE(inode) (inode == inode->i_sb->s_root->d_inode)
+ 
+ #define CAP(p) ((zfs_cap *)p)
+ #define COOKIE(p) ((int32_t *)&((zfs_cap *)p)[1])
+ 
+ /* Hash function which returns (not neccessary unique) inode number. */
+ #define ROTATE_LEFT(x, nbites) ((x << nbites) | (x >> (32 - nbites)))
+ #define HASH(fh) (ROTATE_LEFT(fh->sid, 22) ^ ROTATE_LEFT(fh->dev, 12) ^ fh->ino)
+ 
+ /* ZFS super block. */
+ extern struct super_block *zfs_sb;
+ 
+ /* ZFS inode. */
+ #define ZFS_I(inode) ((struct zfs_inode_info *)inode)
+ struct zfs_inode_info {
+ 	struct inode vfs_inode;
+ 	zfs_fh fh;
+ };
+ 
+ /* Size of hash table of processing requests. */
+ #define REQ_PROCESSING_TABSIZE 32
+ 
+ /* Hash function which returns index of queue in the hash table. */
+ #define INDEX(key) (key % REQ_PROCESSING_TABSIZE)
+ 
+ /* Communication channel between this kernel module and ZFSd. */
+ extern struct channel {
+ 	struct semaphore lock;
+ 	volatile int connected;
+ 
+ 	struct semaphore request_id_lock;
+ 	uint32_t request_id;
+ 
+ 	struct semaphore req_pending_count;
+ 		/* count of requests in the req_pending queue */
+ 	struct semaphore req_pending_lock;
+ 	struct list_head req_pending;
+ 		/* queue of requests which have been prepared
+ 		   but not sent to zfsd yet */
+ 
+ 	struct semaphore req_processing_lock;
+ 	struct list_head req_processing[REQ_PROCESSING_TABSIZE];
+ 		/* hashtable of requests which have been sent to ZFSd
+ 		   but corresponding reply has not been received yet */
+ } channel;
+ 
+ enum request_state {REQ_PENDING, REQ_PROCESSING, REQ_DEQUEUED};
+ 
+ /* Request to ZFSd. */
+ struct request {
+ 	struct semaphore lock;
+ 	enum request_state state;
+ 	unsigned int id;	/* unique request id */
+ 	DC *dc;			/* the message */
+ 	unsigned int length;	/* length of request body (dc.buffer) */
+ 	struct list_head item;	/* item in req_pending
+ 				   or req_processing[] list */
+ 	wait_queue_head_t waitq;
+ 		/* wait queue of kernel threads (actualy only current thread)
+ 		   which have prepared the request but not received the reply */
+ };
+ 
+ #endif
Index: fs/zfs/zfsd_call.c
===================================================================
RCS file: fs/zfs/zfsd_call.c
diff -N fs/zfs/zfsd_call.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- fs/zfs/zfsd_call.c	22 May 2004 12:54:55 -0000	1.14
***************
*** 0 ****
--- 1,639 ----
+ /*
+    Functions to call ZFSd.
+    Copyright (C) 2004 Martin Zlomek
+ 
+    This file is part of ZFS.
+ 
+    ZFS is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+ 
+    ZFS is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+    License for more details.
+ 
+    You should have received a copy of the GNU General Public License along with
+    ZFS; see the file COPYING.  If not, write to the Free Software Foundation,
+    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA;
+    or download it from http://www.gnu.org/licenses/gpl.html
+  */
+ 
+ #include <linux/fs.h>
+ #include <linux/types.h>
+ #include <linux/list.h>
+ #include <linux/wait.h>
+ #include <linux/sched.h>
+ #include <linux/errno.h>
+ #include <linux/compiler.h>
+ #include <asm/semaphore.h>
+ #include <asm/uaccess.h>
+ 
+ #include "zfs.h"
+ #include "data-coding.h"
+ #include "zfs_prot.h"
+ 
+ 
+ /*
+    Send the request and wait for the reply.
+  */
+ int send_request(struct request *req) {
+ 	DECLARE_WAITQUEUE(wait, current);
+ 	long timeout_left;
+ 
+ 	TRACE("%u", req->id);
+ 
+ 	if (!channel.connected) {
+ 		TRACE("%u: zfsd closed communication device", req->id);
+ 		return -EIO;
+ 	}
+ 
+ 	init_MUTEX(&req->lock);
+ 	init_waitqueue_head(&req->waitq);
+ 
+ 	TRACE("%u: sending %u bytes", req->id, req->length);
+ 
+ 	/* Add the request to the queue of pending requests. */
+ 	down(&channel.req_pending_lock);
+ 	list_add_tail(&req->item, &channel.req_pending);
+ 	up(&channel.req_pending_lock);
+ 
+ 	req->state = REQ_PENDING;
+ 
+ 	TRACE("%u: waiting for reply", req->id);
+ 
+ 	add_wait_queue(&req->waitq, &wait);
+ 	set_current_state(TASK_INTERRUPTIBLE);
+ 
+ 	/* Wake up a thread waiting for a request. */
+ 	up(&channel.req_pending_count);
+ 
+ 	/* FIXME: If pre-emptible kernel reschedule right now, this thread will be sleeping probably without timeout.
+ 	   Does exist some kernel lock, or something like down_interruptible_timeout()? */
+ 
+ 	timeout_left = schedule_timeout(ZFS_TIMEOUT * HZ);
+ 	remove_wait_queue(&req->waitq, &wait);
+ 
+ 	down(&req->lock);
+ 
+ 	/* If some error (interrupt or timeout) occurs, remove the request from appropriate queue. */
+ 	switch (req->state) {
+ 		case REQ_PENDING:
+ 			down(&channel.req_pending_count);
+ 			down(&channel.req_pending_lock);
+ 			list_del(&req->item);
+ 			up(&channel.req_pending_lock);
+ 			break;
+ 		case REQ_PROCESSING:
+ 			down(&channel.req_processing_lock);
+ 			list_del(&req->item);
+ 			up(&channel.req_processing_lock);
+ 			break;
+ 		default:
+ 			break;
+ 	}
+ 
+ 	if (signal_pending(current)) {
+ 		TRACE("%u: interrupt", req->id);
+ 		return -EINTR;
+ 	}
+ 	if (!timeout_left) {
+ 		TRACE("%u: timeout", req->id);
+ 		return -ESTALE;
+ 	}
+ 	if (!channel.connected) {
+ 		TRACE("%u: zfsd closed communication device", req->id);
+ 		return -EIO;
+ 	}
+ 
+ 	TRACE("%u: receiving corresponding reply", req->id);
+ 
+ 	/* No up(&req->lock) is neccessary - no critical section follows and the request will be destroyed soon. */
+ 
+ 	return 0;
+ }
+ 
+ int zfsd_root(zfs_fh *fh)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_root_zfsd(&dc, NULL);
+ 	if (!error
+ 	    && (!decode_zfs_fh(dc, fh)
+ 		|| !finish_decoding(dc)))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_getattr(fattr *attr, zfs_fh *fh)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_getattr_zfsd(&dc, fh);
+ 	if (!error
+ 	    && (!decode_fattr(dc, attr)
+ 		|| !finish_decoding(dc)))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_setattr(fattr *attr, sattr_args *args)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_setattr_zfsd(&dc, args);
+ 	if (!error
+ 	    && (!decode_fattr(dc, attr)
+ 		|| !finish_decoding(dc)))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_create(create_res *res, create_args *args)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_create_zfsd(&dc, args);
+ 	if (!error
+ 	    && (!decode_create_res(dc, res)
+ 		|| !finish_decoding(dc)))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_lookup(dir_op_res *res, dir_op_args *args)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_lookup_zfsd(&dc, args);
+ 	if (!error
+ 	    && (!decode_dir_op_res(dc, res)
+ 		|| !finish_decoding(dc)))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_link(link_args *args)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_link_zfsd(&dc, args);
+ 	if (!error
+ 	    && !finish_decoding(dc))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_unlink(dir_op_args *args)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_unlink_zfsd(&dc, args);
+ 	if (!error
+ 	    && !finish_decoding(dc))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_symlink(dir_op_res *res, symlink_args *args)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_symlink_zfsd(&dc, args);
+ 	if (!error
+ 	    && (!decode_dir_op_res(dc, res)
+ 		|| !finish_decoding(dc)))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_mkdir(dir_op_res *res, mkdir_args *args)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_mkdir_zfsd(&dc, args);
+ 	if (!error
+ 	    && (!decode_dir_op_res(dc, res)
+ 		|| !finish_decoding(dc)))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_rmdir(dir_op_args *args)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_rmdir_zfsd(&dc, args);
+ 	if (!error
+ 	    && !finish_decoding(dc))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_mknod(dir_op_res *res, mknod_args *args)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_mknod_zfsd(&dc, args);
+ 	if (!error
+ 	    && (!decode_dir_op_res(dc, res)
+ 		|| !finish_decoding(dc)))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_rename(rename_args *args)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_rename_zfsd(&dc, args);
+ 	if (!error
+ 	    && !finish_decoding(dc))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_readlink(read_link_res *res, zfs_fh *fh)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_readlink_zfsd(&dc, fh);
+ 	if (!error
+ 	    && (!decode_read_link_res(dc, res)
+ 		|| !finish_decoding(dc)))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_open(zfs_cap *cap, open_args *args)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_open_zfsd(&dc, args);
+ 	if (!error
+ 	    && (!decode_zfs_cap(dc, cap)
+ 		|| !finish_decoding(dc)))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_close(zfs_cap *cap)
+ {
+ 	DC *dc;
+ 	int error;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_close_zfsd(&dc, cap);
+ 	if (!error
+ 	    && !finish_decoding(dc))
+ 		error = -EPROTO;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_readdir(read_dir_args *args, struct file *file, void *dirent, filldir_t filldir)
+ {
+ 	DC *dc;
+ 	dir_list list;
+ 	dir_entry entry;
+ 	struct qstr name;
+ 	int error, entries = 0, i;
+ 
+ 	TRACE("");
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	while (1) {
+ 		error = zfs_proc_readdir_zfsd(&dc, args);
+ 		if (error)
+ 			break;
+ 
+ 		if (!decode_dir_list(dc, &list)) {
+ 			error = -EPROTO;
+ 			break;
+ 		}
+ 
+ 		for (i = 0; i < list.n; i++) {
+ 			if (!decode_dir_entry(dc, &entry)) {
+ 				error = -EPROTO;
+ 				break;
+ 			}
+ 
+ 			TRACE("entry: ino=%u, cookie=%d, '%s'", entry.ino, entry.cookie, entry.name.str);
+ 
+ 			name.name = entry.name.str;
+ 			name.len = entry.name.len;
+ 
+ 			error = filldir(dirent, name.name, name.len, file->f_pos, entry.ino, DT_UNKNOWN);
+ 			if (error)
+ 				break;
+ 
+ 			/* Store the cookie to be able to continue list dir. */
+ 			*COOKIE(file->private_data) = entry.cookie;
+ 			file->f_pos++;
+ 			entries++;
+ 		}
+ 		if (error)
+ 			break;
+ 
+ 		if (!finish_decoding(dc)) {
+ 			error = -EPROTO;
+ 			break;
+ 		}
+ 
+ 		if (list.eof) {
+ 			file->f_pos = -1;
+ 			break;
+ 		}
+ 
+ 		args->cookie = entry.cookie;
+ 	}
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", entries ? entries : error);
+ 
+ 	return entries ? entries : error;
+ }
+ 
+ int zfsd_read(char __user *buf, read_args *args)
+ {
+ 	DC *dc;
+ 	uint32_t nbytes;
+ 	int error;
+ 
+ 	TRACE("reading %u bytes", args->count);
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_read_zfsd(&dc, args);
+ 	if (!error) {
+ 		if (!decode_uint32_t(dc, &nbytes)
+ 		    || (nbytes > args->count))
+ 			error = -EPROTO;
+ 		else {
+ 			dc->cur_length += nbytes;
+ 			if (!finish_decoding(dc))
+ 				error = -EPROTO;
+ 			else {
+ 				if (copy_to_user(buf, dc->cur_pos, nbytes))
+ 					error = -EFAULT;
+ 				else
+ 					error = nbytes;
+ 			}
+ 		}
+ 	}
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_write(write_args *args)
+ {
+ 	DC *dc;
+ 	write_res res;
+ 	int error;
+ 
+ 	TRACE("writting %u bytes", args->data.len);
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_write_zfsd(&dc, args);
+ 	if (!error) {
+ 		if (!decode_write_res(dc, &res)
+ 		    || (res.written > args->data.len)
+ 		    || !finish_decoding(dc))
+ 			error = -EPROTO;
+ 		else
+ 			error = res.written;
+ 	} else if (dc->cur_pos == NULL)
+ 		error = -EFAULT;
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
+ 
+ int zfsd_readpage(char *buf, read_args *args)
+ {
+ 	DC *dc;
+ 	uint32_t nbytes;
+ 	int error;
+ 
+ 	TRACE("reading %u bytes", args->count);
+ 
+ 	dc = dc_get();
+ 	if (!dc)
+ 		return -ENOMEM;
+ 
+ 	error = zfs_proc_read_zfsd(&dc, args);
+ 	if (!error) {
+ 		if (!decode_uint32_t(dc, &nbytes)
+ 		    || (nbytes > args->count))
+ 			error = -EPROTO;
+ 		else {
+ 			dc->cur_length += nbytes;
+ 			if (!finish_decoding(dc))
+ 				error = -EPROTO;
+ 			else {
+ 				memcpy(buf, dc->cur_pos, nbytes);
+ 				error = nbytes;
+ 			}
+ 		}
+ 	}
+ 
+ 	dc_put(dc);
+ 
+ 	TRACE("%d", error);
+ 
+ 	return error;
+ }
Index: fs/zfs/zfsd_call.h
===================================================================
RCS file: fs/zfs/zfsd_call.h
diff -N fs/zfs/zfsd_call.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- fs/zfs/zfsd_call.h	20 May 2004 14:20:08 -0000	1.9
***************
*** 0 ****
--- 1,54 ----
+ /*
+    Functions to call ZFSd.
+    Copyright (C) 2004 Martin Zlomek
+ 
+    This file is part of ZFS.
+ 
+    ZFS is free software; you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+ 
+    ZFS is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+    License for more details.
+ 
+    You should have received a copy of the GNU General Public License along with
+    ZFS; see the file COPYING.  If not, write to the Free Software Foundation,
+    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA;
+    or download it from http://www.gnu.org/licenses/gpl.html
+  */
+ 
+ #ifndef _ZFSD_CALL_H
+ #define _ZFSD_CALL_H
+ 
+ #include <linux/fs.h>
+ #include <linux/compiler.h>
+ 
+ #include "zfs.h"
+ #include "zfs_prot.h"
+ 
+ 
+ extern int send_request(struct request *req);
+ extern int zfsd_root(zfs_fh *fh);
+ extern int zfsd_getattr(fattr *attr, zfs_fh *fh);
+ extern int zfsd_setattr(fattr *attr, sattr_args *args);
+ extern int zfsd_create(create_res *res, create_args *args);
+ extern int zfsd_lookup(dir_op_res *res, dir_op_args *args);
+ extern int zfsd_link(link_args *args);
+ extern int zfsd_unlink(dir_op_args *args);
+ extern int zfsd_symlink(dir_op_res *res, symlink_args *args);
+ extern int zfsd_mkdir(dir_op_res *res, mkdir_args *args);
+ extern int zfsd_rmdir(dir_op_args *args);
+ extern int zfsd_mknod(dir_op_res *res, mknod_args *args);
+ extern int zfsd_rename(rename_args *args);
+ extern int zfsd_readlink(read_link_res *res, zfs_fh *fh);
+ extern int zfsd_open(zfs_cap *cap, open_args *args);
+ extern int zfsd_close(zfs_cap *cap);
+ extern int zfsd_readdir(read_dir_args *args, struct file *file, void *dirent, filldir_t filldir);
+ extern int zfsd_read(char __user *buf, read_args *args);
+ extern int zfsd_write(write_args *args);
+ extern int zfsd_readpage(char *buf, read_args *args);
+ 
+ #endif

