summaryrefslogtreecommitdiffstats
path: root/fs/coda
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
commit27cfca1ec98e91261b1a5355d10a8996464b63af (patch)
tree8e895a53e372fa682b4c0a585b9377d67ed70d0e /fs/coda
parent6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff)
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too o Upgrade to 2.1.89. Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'fs/coda')
-rw-r--r--fs/coda/.cvsignore1
-rw-r--r--fs/coda/Makefile4
-rw-r--r--fs/coda/cache.c349
-rw-r--r--fs/coda/cnode.c148
-rw-r--r--fs/coda/coda_linux.c236
-rw-r--r--fs/coda/dir.c278
-rw-r--r--fs/coda/file.c74
-rw-r--r--fs/coda/inode.c34
-rw-r--r--fs/coda/namecache.c832
-rw-r--r--fs/coda/pioctl.c15
-rw-r--r--fs/coda/psdev.c303
-rw-r--r--fs/coda/super.c444
-rw-r--r--fs/coda/symlink.c53
-rw-r--r--fs/coda/sysctl.c28
-rw-r--r--fs/coda/upcall.c781
15 files changed, 1637 insertions, 1943 deletions
diff --git a/fs/coda/.cvsignore b/fs/coda/.cvsignore
index 4671378ae..857dd22e9 100644
--- a/fs/coda/.cvsignore
+++ b/fs/coda/.cvsignore
@@ -1 +1,2 @@
.depend
+.*.flags
diff --git a/fs/coda/Makefile b/fs/coda/Makefile
index 4118fdc61..0a4140745 100644
--- a/fs/coda/Makefile
+++ b/fs/coda/Makefile
@@ -3,8 +3,8 @@
#
O_TARGET := coda.o
-O_OBJS := psdev.o upcall.o cnode.o super.o dir.o coda_linux.o symlink.o pioctl.o file.o namecache.o\
- sysctl.o
+O_OBJS := psdev.o cache.o cnode.o super.o dir.o file.o upcall.o coda_linux.o\
+ symlink.o pioctl.o sysctl.o
M_OBJS := $(O_TARGET)
# If you want debugging output, please uncomment the following line
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
new file mode 100644
index 000000000..7673bfbdd
--- /dev/null
+++ b/fs/coda/cache.c
@@ -0,0 +1,349 @@
+/*
+ * Cache operations for Coda.
+ * For Linux 2.1: (C) 1997 Carnegie Mellon University
+ *
+ * Carnegie Mellon encourages users of this code to contribute improvements
+ * to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/locks.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <linux/string.h>
+#include <linux/list.h>
+
+#include <linux/coda.h>
+#include <linux/coda_linux.h>
+#include <linux/coda_psdev.h>
+#include <linux/coda_fs_i.h>
+#include <linux/coda_cache.h>
+
+/* Keep various stats */
+struct cfsnc_statistics cfsnc_stat;
+
+
+/* we need to call INIT_LIST_HEAD on cnp->c_cnhead and sbi->sbi_cchead */
+
+void coda_ccinsert(struct coda_cache *el, struct super_block *sb)
+{
+ struct coda_sb_info *sbi = coda_sbp(sb);
+ENTRY;
+ if ( !sbi || !el) {
+ printk("coda_ccinsert: NULL sbi or el!\n");
+ return ;
+ }
+
+ list_add(&el->cc_cclist, &sbi->sbi_cchead);
+}
+
+void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cnp)
+{
+ENTRY;
+ if ( !cnp || !el) {
+ printk("coda_cninsert: NULL cnp or el!\n");
+ return ;
+ }
+ list_add(&el->cc_cnlist, &cnp->c_cnhead);
+}
+
+void coda_ccremove(struct coda_cache *el)
+{
+ ENTRY;
+ if (el->cc_cclist.next && el->cc_cclist.prev)
+ list_del(&el->cc_cclist);
+ else
+ printk("coda_cnremove: trying to remove 0 entry!");
+}
+
+void coda_cnremove(struct coda_cache *el)
+{
+ ENTRY;
+ if (el->cc_cnlist.next && el->cc_cnlist.prev)
+ list_del(&el->cc_cnlist);
+ else
+ printk("coda_cnremove: trying to remove 0 entry!");
+}
+
+
+void coda_cache_create(struct inode *inode, int mask)
+{
+ struct coda_inode_info *cnp = ITOC(inode);
+ struct super_block *sb = inode->i_sb;
+ struct coda_cache *cc = NULL;
+ ENTRY;
+ CODA_ALLOC(cc, struct coda_cache *, sizeof(*cc));
+
+ if ( !cc ) {
+ printk("Out of memory in coda_cache_enter!\n");
+ return;
+ }
+ coda_load_creds(&cc->cc_cred);
+ cc->cc_mask = mask;
+ coda_cninsert(cc, cnp);
+ coda_ccinsert(cc, sb);
+}
+
+struct coda_cache * coda_cache_find(struct inode *inode)
+{
+ struct coda_inode_info *cnp = ITOC(inode);
+ struct list_head *lh, *le;
+ struct coda_cache *cc = NULL;
+
+ le = lh = &cnp->c_cnhead;
+ while( (le = le->next ) != lh ) {
+ /* compare name and creds */
+ cc = list_entry(le, struct coda_cache, cc_cnlist);
+ if ( !coda_cred_ok(&cc->cc_cred) )
+ continue;
+ CDEBUG(D_CACHE, "HIT for ino %ld\n", inode->i_ino );
+ return cc; /* cache hit */
+ }
+ return NULL;
+}
+
+void coda_cache_enter(struct inode *inode, int mask)
+{
+ struct coda_cache *cc;
+
+ cc = coda_cache_find(inode);
+
+ if ( cc ) {
+ cc->cc_mask |= mask;
+ } else {
+ coda_cache_create(inode, mask);
+ }
+}
+
+void coda_cache_clear_cnp(struct coda_inode_info *cnp)
+{
+ struct list_head *lh, *le;
+ struct coda_cache *cc;
+
+ if ( !cnp ) {
+ printk("coda_cache_cnp_clear: NULL cnode\n");
+ return;
+ }
+
+ lh = le = &cnp->c_cnhead;
+ while ( (le = le->next ) != lh ) {
+ cc = list_entry(le, struct coda_cache, cc_cnlist);
+ coda_cnremove(cc);
+ coda_ccremove(cc);
+ CODA_FREE(cc, sizeof(*cc));
+ }
+}
+
+void coda_cache_clear_all(struct super_block *sb)
+{
+ struct list_head *lh, *le;
+ struct coda_cache *cc;
+ struct coda_sb_info *sbi = coda_sbp(sb);
+
+ if ( !sbi ) {
+ printk("coda_cache_clear_all: NULL sbi\n");
+ return;
+ }
+
+ lh = le = &sbi->sbi_cchead;
+ while ( (le = le->next ) != lh ) {
+ cc = list_entry(le, struct coda_cache, cc_cclist);
+ coda_cnremove(cc);
+ coda_ccremove(cc);
+ CODA_FREE(cc, sizeof(*cc));
+ }
+}
+
+void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred)
+{
+ struct list_head *lh, *le;
+ struct coda_cache *cc;
+ struct coda_sb_info *sbi = coda_sbp(sb);
+
+ if ( !sbi ) {
+ printk("coda_cache_clear_all: NULL sbi\n");
+ return;
+ }
+
+ lh = le = &sbi->sbi_cchead;
+ while ( (le = le->next ) != lh ) {
+ cc = list_entry(le, struct coda_cache, cc_cclist);
+ if ( coda_cred_eq(&cc->cc_cred, cred)) {
+ coda_cnremove(cc);
+ coda_ccremove(cc);
+ CODA_FREE(cc, sizeof(*cc));
+ }
+ }
+}
+
+
+int coda_cache_check(struct inode *inode, int mask)
+{
+ struct coda_inode_info *cnp = ITOC(inode);
+ struct list_head *lh, *le;
+ struct coda_cache *cc = NULL;
+
+ le = lh = &cnp->c_cnhead;
+ while( (le = le->next ) != lh ) {
+ /* compare name and creds */
+ cc = list_entry(le, struct coda_cache, cc_cnlist);
+ if ( (cc->cc_mask & mask) != mask )
+ continue;
+ if ( !coda_cred_ok(&cc->cc_cred) )
+ continue;
+ CDEBUG(D_CACHE, "HIT for ino %ld\n", inode->i_ino );
+ return 1; /* cache hit */
+ }
+ CDEBUG(D_CACHE, "MISS for ino %ld\n", inode->i_ino );
+ return 0;
+}
+
+
+/* DENTRY related stuff */
+
+/* when the dentry count falls to 0 this is called. If Venus has
+ asked for it to be flushed, we take it out of the dentry hash
+ table with d_drop */
+
+static void coda_flag_children(struct dentry *parent)
+{
+ struct list_head *child;
+ struct coda_inode_info *cnp;
+ struct dentry *de;
+
+ child = parent->d_subdirs.next;
+ while ( child != &parent->d_subdirs ) {
+ de = list_entry(child, struct dentry, d_child);
+ cnp = ITOC(de->d_inode);
+ if (cnp)
+ cnp->c_flags |= C_ZAPFID;
+ CDEBUG(D_CACHE, "ZAPFID for %s\n", coda_f2s(&cnp->c_fid));
+
+ child = child->next;
+ }
+ return;
+}
+
+/* flag dentry and possibly children of a dentry with C_ZAPFID */
+void coda_dentry_delete(struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ struct coda_inode_info *cnp = NULL;
+ ENTRY;
+
+ if (inode) {
+ cnp = ITOC(inode);
+ if ( cnp )
+ CHECK_CNODE(cnp);
+ } else {
+ CDEBUG(D_CACHE, "No inode for dentry_delete!\n");
+ return;
+ }
+
+
+ if ( !cnp ) {
+ printk("No cnode for dentry_delete!\n");
+ return;
+ }
+
+ if ( cnp->c_flags & (C_ZAPFID | C_ZAPDIR) )
+ d_drop(dentry);
+ if ( (cnp->c_flags & C_ZAPDIR) && S_ISDIR(inode->i_mode) ) {
+ coda_flag_children(dentry);
+ }
+ return;
+}
+
+static void coda_zap_cnode(struct coda_inode_info *cnp, int flags)
+{
+ cnp->c_flags |= flags;
+ coda_cache_clear_cnp(cnp);
+}
+
+
+
+/* the dache will notice the flags and drop entries (possibly with
+ children) the moment they are no longer in use */
+void coda_zapfid(struct ViceFid *fid, struct super_block *sb, int flag)
+{
+ struct inode *inode = NULL;
+ struct coda_inode_info *cnp;
+
+ ENTRY;
+
+ if ( !sb ) {
+ printk("coda_zapfid: no sb!\n");
+ return;
+ }
+
+ if ( !fid ) {
+ printk("coda_zapfid: no fid!\n");
+ return;
+ }
+
+ if ( coda_fid_is_volroot(fid) ) {
+ struct list_head *lh, *le;
+ struct coda_sb_info *sbi = coda_sbp(sb);
+ le = lh = &sbi->sbi_volroothead;
+ while ( (le = le->next) != lh ) {
+ cnp = list_entry(le, struct coda_inode_info, c_volrootlist);
+ if ( cnp->c_fid.Volume == fid->Volume)
+ coda_zap_cnode(cnp, flag);
+ }
+ return;
+ }
+
+
+ inode = coda_fid_to_inode(fid, sb);
+ if ( !inode ) {
+ CDEBUG(D_CACHE, "coda_zapfid: no inode!\n");
+ return;
+ }
+ cnp = ITOC(inode);
+ coda_zap_cnode(cnp, flag);
+}
+
+
+int
+cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ int len=0;
+ off_t begin;
+
+ /* cfsnc_gather_stats(); */
+
+ /* this works as long as we are below 1024 characters! */
+ len += sprintf(buffer,"Coda minicache statistics\n\n");
+ len += sprintf(buffer+len, "cfsnc_hits : %d\n", cfsnc_stat.hits);
+ len += sprintf(buffer+len, "cfsnc_misses : %d\n", cfsnc_stat.misses);
+ len += sprintf(buffer+len, "cfsnc_enters : %d\n", cfsnc_stat.enters);
+ len += sprintf(buffer+len, "cfsnc_dbl_enters : %d\n", cfsnc_stat.dbl_enters);
+ len += sprintf(buffer+len, "cfsnc_long_name_enters : %d\n", cfsnc_stat.long_name_enters);
+ len += sprintf(buffer+len, "cfsnc_long_name_lookups : %d\n", cfsnc_stat.long_name_lookups);
+ len += sprintf(buffer+len, "cfsnc_long_remove : %d\n", cfsnc_stat.long_remove);
+ len += sprintf(buffer+len, "cfsnc_lru_rm : %d\n", cfsnc_stat.lru_rm);
+ len += sprintf(buffer+len, "cfsnc_zapPfids : %d\n", cfsnc_stat.zapPfids);
+ len += sprintf(buffer+len, "cfsnc_zapFids : %d\n", cfsnc_stat.zapFids);
+ len += sprintf(buffer+len, "cfsnc_zapFile : %d\n", cfsnc_stat.zapFile);
+ len += sprintf(buffer+len, "cfsnc_zapUsers : %d\n", cfsnc_stat.zapUsers);
+ len += sprintf(buffer+len, "cfsnc_Flushes : %d\n", cfsnc_stat.Flushes);
+ len += sprintf(buffer+len, "cfsnc_SumLen : %d\n", cfsnc_stat.Sum_bucket_len);
+ len += sprintf(buffer+len, "cfsnc_Sum2Len : %d\n", cfsnc_stat.Sum2_bucket_len);
+ len += sprintf(buffer+len, "cfsnc_# 0 len : %d\n", cfsnc_stat.Num_zero_len);
+ len += sprintf(buffer+len, "cfsnc_MaxLen : %d\n", cfsnc_stat.Max_bucket_len);
+ len += sprintf(buffer+len, "cfsnc_SearchLen : %d\n", cfsnc_stat.Search_len);
+ begin = offset;
+ *start = buffer + begin;
+ len -= begin;
+
+ if(len>length)
+ len = length;
+ if (len< 0)
+ len = 0;
+ return len;
+}
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index abf8a855f..67133f275 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -1,5 +1,5 @@
/* cnode related routines for the coda kernel code
- Peter Braam, Sep 1996.
+ (C) 1996 Peter Braam
*/
#include <linux/types.h>
@@ -7,39 +7,38 @@
#include <linux/coda.h>
#include <linux/coda_linux.h>
+#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
-#include <linux/coda_cnode.h>
extern int coda_debug;
extern int coda_print_entry;
-extern int coda_fetch_inode(struct inode *inode, struct coda_vattr *attr);
/* cnode.c */
-struct cnode *coda_cnode_alloc(void);
-void coda_cnode_free(struct cnode *);
-int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb);
-/* return pointer to new empty cnode */
-struct cnode *coda_cnode_alloc(void)
-{
- struct cnode *result = NULL;
- CODA_ALLOC(result, struct cnode *, sizeof(struct cnode));
- if ( !result ) {
- printk("coda_cnode_alloc: kmalloc returned NULL.\n");
- return result;
+
+static void coda_fill_inode (struct inode *inode, struct coda_vattr *attr)
+{
+ CDEBUG(D_SUPER, "ino: %ld\n", inode->i_ino);
+
+ if (coda_debug & D_SUPER )
+ print_vattr(attr);
+
+ coda_vattr_to_iattr(inode, attr);
+
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &coda_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode))
+ inode->i_op = &coda_dir_inode_operations;
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &coda_symlink_inode_operations;
+ else {
+ printk ("coda_read_inode: what's this? i_mode = %o\n",
+ inode->i_mode);
+ inode->i_op = NULL;
}
-
- memset(result, 0, (int) sizeof(struct cnode));
- return result;
}
-/* release cnode memory */
-void coda_cnode_free(struct cnode *cinode)
-{
- CODA_FREE(cinode, sizeof(struct cnode));
-}
-
/* this is effectively coda_iget:
- get attributes (might be cached)
- get the inode for the fid using vfs iget
@@ -48,11 +47,11 @@ void coda_cnode_free(struct cnode *cinode)
*/
int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
{
- struct cnode *cnp;
+ struct coda_inode_info *cnp;
+ struct coda_sb_info *sbi= coda_sbp(sb);
struct coda_vattr attr;
int error;
ino_t ino;
- char str[50];
ENTRY;
@@ -63,7 +62,7 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
error = venus_getattr(sb, fid, &attr);
if ( error ) {
printk("coda_cnode_make: coda_getvattr returned %d for %s.\n",
- error, coda_f2s(fid, str));
+ error, coda_f2s(fid));
*inode = NULL;
return error;
}
@@ -75,37 +74,26 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
return -ENOMEM;
}
- /* link the cnode and the vfs inode
- if this inode is not linked yet
- */
- if ( !(*inode)->u.generic_ip ) {
- cnp = coda_cnode_alloc();
- if ( !cnp ) {
- printk("coda_cnode_make: coda_cnode_alloc failed.\n");
- clear_inode(*inode);
- return -ENOMEM;
- }
- cnp->c_fid = *fid;
- cnp->c_magic = CODA_CNODE_MAGIC;
+ cnp = ITOC(*inode);
+ if ( cnp->c_magic == 0 ) {
+ memset(cnp, 0, (int) sizeof(struct coda_inode_info));
+ cnp->c_fid = *fid;
+ cnp->c_magic = CODA_CNODE_MAGIC;
cnp->c_flags = C_VATTR;
- cnp->c_vnode = *inode;
- (*inode)->u.generic_ip = (void *) cnp;
- CDEBUG(D_CNODE, "LINKING: ino %ld, count %d at 0x%x with cnp 0x%x, cnp->c_vnode 0x%x, in->u.generic_ip 0x%x\n", (*inode)->i_ino, (*inode)->i_count, (int) (*inode), (int) cnp, (int)cnp->c_vnode, (int) (*inode)->u.generic_ip);
+ cnp->c_vnode = *inode;
+ INIT_LIST_HEAD(&(cnp->c_cnhead));
+ INIT_LIST_HEAD(&(cnp->c_volrootlist));
} else {
- cnp = (struct cnode *)(*inode)->u.generic_ip;
- CDEBUG(D_CNODE, "FOUND linked: ino %ld, count %d, at 0x%x with cnp 0x%x, cnp->c_vnode 0x%x\n", (*inode)->i_ino, (*inode)->i_count, (int) (*inode), (int) cnp, (int)cnp->c_vnode);
+ printk("coda_cnode make on initialized inode %ld, %s!\n",
+ (*inode)->i_ino, coda_f2s(&cnp->c_fid));
}
- CHECK_CNODE(cnp);
-
- /* refresh the attributes */
- error = coda_fetch_inode(*inode, &attr);
- if ( error ) {
- printk("coda_cnode_make: fetch_inode returned %d\n", error);
- clear_inode(*inode);
- coda_cnode_free(cnp);
- return -error;
- }
- CDEBUG(D_CNODE, "Done linking: ino %ld, at 0x%x with cnp 0x%x, cnp->c_vnode 0x%x\n", (*inode)->i_ino, (int) (*inode), (int) cnp, (int)cnp->c_vnode);
+
+ /* fill in the inode attributes */
+ if ( coda_fid_is_volroot(fid) )
+ list_add(&cnp->c_volrootlist, &sbi->sbi_volroothead);
+
+ coda_fill_inode(*inode, &attr);
+ CDEBUG(D_CNODE, "Done linking: ino %ld, at 0x%x with cnp 0x%x, cnp->c_vnode 0x%x\n", (*inode)->i_ino, (int) (*inode), (int) cnp, (int)cnp->c_vnode);
EXIT;
return 0;
@@ -122,51 +110,35 @@ inline int coda_fideq(ViceFid *fid1, ViceFid *fid2)
}
-/* compute the inode number from the FID
- same routine as in vproc.cc (venus)
- XXX look at the exceptional case of root fids etc
-*/
-static ino_t
-coda_fid2ino(ViceFid *fid)
-{
- u_long ROOT_VNODE = 1;
- u_long ROOT_UNIQUE = 1;
- ViceFid nullfid = { 0, 0, 0};
-
- if ( coda_fideq(fid, &nullfid) ) {
- printk("coda_fid2ino: called with NULL Fid!\n");
- return 0;
- }
-
- /* what do we return for the root fid */
-
- /* Other volume root. We need the relevant mount point's
- fid, but we don't know what that is! */
- if (fid->Vnode == ROOT_VNODE && fid->Unique == ROOT_UNIQUE) {
- return(0);
- }
-
- /* Non volume root. */
- return(fid->Unique + (fid->Vnode << 10) + (fid->Volume << 20));
-}
/* convert a fid to an inode. Avoids having a hash table
such as present in the Mach minicache */
-struct inode *
-coda_fid2inode(ViceFid *fid, struct super_block *sb) {
+struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
+{
ino_t nr;
struct inode *inode;
- struct cnode *cnp;
-
- nr = coda_fid2ino(fid);
+ struct coda_inode_info *cnp;
+ENTRY;
+
+ CDEBUG(D_INODE, "%s\n", coda_f2s(fid));
+
+ nr = coda_f2i(fid);
inode = iget(sb, nr);
+ if ( !inode ) {
+ printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n",
+ sb, nr);
+ return NULL;
+ }
+
/* check if this inode is linked to a cnode */
- cnp = (struct cnode *) inode->u.generic_ip;
- if ( cnp == NULL ) {
+ cnp = ITOC(inode);
+
+ if ( cnp->c_magic != CODA_CNODE_MAGIC ) {
iput(inode);
return NULL;
}
+
/* make sure fid is the one we want */
if ( !coda_fideq(fid, &(cnp->c_fid)) ) {
printk("coda_fid2inode: bad cnode! Tell Peter.\n");
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index ea595c35b..e968f3add 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -21,24 +21,33 @@
#include <linux/coda.h>
#include <linux/coda_linux.h>
#include <linux/coda_psdev.h>
-#include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_fs_i.h>
+#include <linux/coda_cache.h>
/* initialize the debugging variables */
-int coda_debug =815;
-int coda_print_entry = 1;
+int coda_debug = 0;
+int coda_print_entry = 0;
int coda_access_cache = 1;
/* caller must allocate 36 byte string ! */
-char * coda_f2s(ViceFid *f, char *s)
+char * coda_f2s(ViceFid *f)
{
+ static char s[50];
if ( f ) {
- sprintf(s, "(%-#10lx,%-#10lx,%-#10lx)",
+ sprintf(s, "(%10lx,%10lx,%10lx)",
f->Volume, f->Vnode, f->Unique);
}
return s;
}
+int coda_iscontrol(const char *name, size_t length)
+{
+ if ((CFS_CONTROLLEN == length) &&
+ (strncmp(name, CFS_CONTROL, CFS_CONTROLLEN) == 0))
+ return 1;
+ return 0;
+}
+
int coda_isroot(struct inode *i)
{
if ( i->i_sb->s_root->d_inode == i ) {
@@ -47,11 +56,10 @@ int coda_isroot(struct inode *i)
return 0;
}
}
+
-void coda_load_creds(struct CodaCred *cred)
+void coda_load_creds(struct coda_cred *cred)
{
- int i;
-
cred->cr_uid = (vuid_t) current->uid;
cred->cr_euid = (vuid_t) current->euid;
cred->cr_suid = (vuid_t) current->suid;
@@ -61,10 +69,216 @@ void coda_load_creds(struct CodaCred *cred)
cred->cr_egid = (vgid_t) current->egid;
cred->cr_sgid = (vgid_t) current->sgid;
cred->cr_fsgid = (vgid_t) current->fsgid;
+}
+
+int coda_cred_ok(struct coda_cred *cred)
+{
+ return(current->fsuid == cred->cr_fsuid);
+}
+
+int coda_cred_eq(struct coda_cred *cred1, struct coda_cred *cred2)
+{
+ return (cred1->cr_fsuid == cred2->cr_fsuid);
+}
+
+unsigned short coda_flags_to_cflags(unsigned short flags)
+{
+ unsigned short coda_flags = 0;
+
+ if ( flags & (O_RDONLY | O_RDWR) )
+ coda_flags |= C_O_READ;
+
+ if ( flags & (O_WRONLY | O_RDWR) )
+ coda_flags |= C_O_WRITE;
+
+ if ( flags & O_TRUNC )
+ coda_flags |= C_O_TRUNC;
+
+ return coda_flags;
+}
+
+
+int coda_fid_is_volroot(struct ViceFid *fid)
+{
+ return ( (fid->Vnode == 1) && (fid->Unique == 1 ) );
+}
- for ( i = 0 ; i < NGROUPS ; ++i ) {
- cred->cr_groups[i] = (vgid_t) current->groups[i];
+/* utility functions below */
+void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
+{
+ int inode_type;
+ /* inode's i_dev, i_flags, i_ino are set by iget
+ XXX: is this all we need ??
+ */
+ switch (attr->va_type) {
+ case C_VNON:
+ inode_type = 0;
+ break;
+ case C_VREG:
+ inode_type = S_IFREG;
+ break;
+ case C_VDIR:
+ inode_type = S_IFDIR;
+ break;
+ case C_VLNK:
+ inode_type = S_IFLNK;
+ break;
+ default:
+ inode_type = 0;
}
+ inode->i_mode |= inode_type;
+ if (attr->va_mode != (u_short) -1)
+ inode->i_mode = attr->va_mode | inode_type;
+ if (attr->va_uid != -1)
+ inode->i_uid = (uid_t) attr->va_uid;
+ if (attr->va_gid != -1)
+ inode->i_gid = (gid_t) attr->va_gid;
+ if (attr->va_nlink != -1)
+ inode->i_nlink = attr->va_nlink;
+ if (attr->va_size != -1)
+ inode->i_size = attr->va_size;
+ /* XXX This needs further study */
+ /*
+ inode->i_blksize = attr->va_blocksize;
+ inode->i_blocks = attr->va_size/attr->va_blocksize
+ + (attr->va_size % attr->va_blocksize ? 1 : 0);
+ */
+ if (attr->va_atime.tv_sec != -1)
+ inode->i_atime = attr->va_atime.tv_sec;
+ if (attr->va_mtime.tv_sec != -1)
+ inode->i_mtime = attr->va_mtime.tv_sec;
+ if (attr->va_ctime.tv_sec != -1)
+ inode->i_ctime = attr->va_ctime.tv_sec;
}
+/*
+ * BSD sets attributes that need not be modified to -1.
+ * Linux uses the valid field to indicate what should be
+ * looked at. The BSD type field needs to be deduced from linux
+ * mode.
+ * So we have to do some translations here.
+ */
+
+void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr)
+{
+ unsigned int valid;
+
+ /* clean out */
+ vattr->va_mode = (umode_t) -1;
+ vattr->va_uid = (vuid_t) -1;
+ vattr->va_gid = (vgid_t) -1;
+ vattr->va_size = (off_t) -1;
+ vattr->va_atime.tv_sec = (time_t) -1;
+ vattr->va_mtime.tv_sec = (time_t) -1;
+ vattr->va_ctime.tv_sec = (time_t) -1;
+ vattr->va_atime.tv_nsec = (time_t) -1;
+ vattr->va_mtime.tv_nsec = (time_t) -1;
+ vattr->va_ctime.tv_nsec = (time_t) -1;
+ vattr->va_type = C_VNON;
+ vattr->va_fileid = -1;
+ vattr->va_gen = -1;
+ vattr->va_bytes = -1;
+ vattr->va_nlink = -1;
+ vattr->va_blocksize = -1;
+ vattr->va_rdev = -1;
+ vattr->va_flags = 0;
+ /* determine the type */
+#if 0
+ mode = iattr->ia_mode;
+ if ( S_ISDIR(mode) ) {
+ vattr->va_type = C_VDIR;
+ } else if ( S_ISREG(mode) ) {
+ vattr->va_type = C_VREG;
+ } else if ( S_ISLNK(mode) ) {
+ vattr->va_type = C_VLNK;
+ } else {
+ /* don't do others */
+ vattr->va_type = C_VNON;
+ }
+#endif
+
+ /* set those vattrs that need change */
+ valid = iattr->ia_valid;
+ if ( valid & ATTR_MODE ) {
+ vattr->va_mode = iattr->ia_mode;
+ }
+ if ( valid & ATTR_UID ) {
+ vattr->va_uid = (vuid_t) iattr->ia_uid;
+ }
+ if ( valid & ATTR_GID ) {
+ vattr->va_gid = (vgid_t) iattr->ia_gid;
+ }
+ if ( valid & ATTR_SIZE ) {
+ vattr->va_size = iattr->ia_size;
+ }
+ if ( valid & ATTR_ATIME ) {
+ vattr->va_atime.tv_sec = iattr->ia_atime;
+ vattr->va_atime.tv_nsec = 0;
+ }
+ if ( valid & ATTR_MTIME ) {
+ vattr->va_mtime.tv_sec = iattr->ia_mtime;
+ vattr->va_mtime.tv_nsec = 0;
+ }
+ if ( valid & ATTR_CTIME ) {
+ vattr->va_ctime.tv_sec = iattr->ia_ctime;
+ vattr->va_ctime.tv_nsec = 0;
+ }
+
+}
+
+void print_vattr(struct coda_vattr *attr)
+{
+ char *typestr;
+
+ switch (attr->va_type) {
+ case C_VNON:
+ typestr = "C_VNON";
+ break;
+ case C_VREG:
+ typestr = "C_VREG";
+ break;
+ case C_VDIR:
+ typestr = "C_VDIR";
+ break;
+ case C_VBLK:
+ typestr = "C_VBLK";
+ break;
+ case C_VCHR:
+ typestr = "C_VCHR";
+ break;
+ case C_VLNK:
+ typestr = "C_VLNK";
+ break;
+ case C_VSOCK:
+ typestr = "C_VSCK";
+ break;
+ case C_VFIFO:
+ typestr = "C_VFFO";
+ break;
+ case C_VBAD:
+ typestr = "C_VBAD";
+ break;
+ default:
+ typestr = "????";
+ break;
+ }
+
+
+ printk("attr: type %s (%o) mode %o uid %d gid %d rdev %d\n",
+ typestr, (int)attr->va_type, (int)attr->va_mode,
+ (int)attr->va_uid, (int)attr->va_gid, (int)attr->va_rdev);
+
+ printk(" fileid %d nlink %d size %d blocksize %d bytes %d\n",
+ (int)attr->va_fileid, (int)attr->va_nlink,
+ (int)attr->va_size,
+ (int)attr->va_blocksize,(int)attr->va_bytes);
+ printk(" gen %ld flags %ld\n",
+ attr->va_gen, attr->va_flags);
+ printk(" atime sec %d nsec %d\n",
+ (int)attr->va_atime.tv_sec, (int)attr->va_atime.tv_nsec);
+ printk(" mtime sec %d nsec %d\n",
+ (int)attr->va_mtime.tv_sec, (int)attr->va_mtime.tv_nsec);
+ printk(" ctime sec %d nsec %d\n",
+ (int)attr->va_ctime.tv_sec, (int)attr->va_ctime.tv_nsec);
+}
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index cfc10dc83..dd20499dc 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -1,5 +1,5 @@
/*
- * Direcotry operations for Coda filesystem
+ * Directory operations for Coda filesystem
* Original version: (C) 1996 P. Braam and M. Callahan
* Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
*
@@ -21,13 +21,13 @@
#include <linux/coda.h>
#include <linux/coda_linux.h>
#include <linux/coda_psdev.h>
-#include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_fs_i.h>
+#include <linux/coda_cache.h>
/* dir inode-ops */
static int coda_create(struct inode *dir, struct dentry *new, int mode);
static int coda_lookup(struct inode *dir, struct dentry *target);
-static int coda_link(struct inode *old_inode, struct inode *dir_inode,
+static int coda_link(struct dentry *old_dentry, struct inode *dir_inode,
struct dentry *entry);
static int coda_unlink(struct inode *dir_inode, struct dentry *entry);
static int coda_symlink(struct inode *dir_inode, struct dentry *entry,
@@ -43,8 +43,15 @@ static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
/* support routines */
static int coda_venus_readdir(struct file *filp, void *dirent,
filldir_t filldir);
+int coda_fsync(struct file *, struct dentry *dentry);
-
+struct dentry_operations coda_dentry_operations =
+{
+ NULL, /* revalidate */
+ NULL, /* hash */
+ NULL,
+ coda_dentry_delete
+};
struct inode_operations coda_dir_inode_operations =
{
@@ -80,7 +87,10 @@ struct file_operations coda_dir_operations = {
NULL, /* mmap */
coda_open, /* open */
coda_release, /* release */
- NULL, /* fsync */
+ coda_fsync, /* fsync */
+ NULL,
+ NULL,
+ NULL
};
@@ -88,14 +98,14 @@ struct file_operations coda_dir_operations = {
/* acces routines: lookup, readlink, permission */
static int coda_lookup(struct inode *dir, struct dentry *entry)
{
- struct cnode *dircnp, *savedcnp;
+ struct coda_inode_info *dircnp;
struct inode *res_inode = NULL;
struct ViceFid resfid;
+ int dropme = 0; /* to indicate entry should not be cached */
int type;
int error = 0;
const char *name = entry->d_name.name;
size_t length = entry->d_name.len;
- char str[50];
ENTRY;
CDEBUG(D_INODE, "name %s, len %d in ino %ld\n",
@@ -110,79 +120,56 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
CHECK_CNODE(dircnp);
if ( length > CFS_MAXNAMLEN ) {
- printk("name too long: lookup, %s (%s)\n",
- coda_f2s(&dircnp->c_fid, str), name);
+ printk("name too long: lookup, %s (%*s)\n",
+ coda_f2s(&dircnp->c_fid), length, name);
return -ENAMETOOLONG;
}
- CDEBUG(D_INODE, "lookup: %s in %s\n", name,
- coda_f2s(&dircnp->c_fid, str));
+ CDEBUG(D_INODE, "lookup: %*s in %s\n", length, name,
+ coda_f2s(&dircnp->c_fid));
/* control object, create inode on the fly */
- if ( coda_isroot(dir) && (CFS_CONTROLLEN == length) &&
- (strncmp(name, CFS_CONTROL, CFS_CONTROLLEN) == 0) ) {
+ if (coda_isroot(dir) && coda_iscontrol(name, length)) {
error = coda_cnode_makectl(&res_inode, dir->i_sb);
CDEBUG(D_SPECIAL,
- "Lookup on CTL object; iput of ino %ld, count %d\n",
+ "Lookup on CTL object; dir ino %ld, count %d\n",
dir->i_ino, dir->i_count);
goto exit;
}
- /* do we have it already in name cache */
- if ( (savedcnp = cfsnc_lookup(dircnp, name, length)) != NULL ) {
- CHECK_CNODE(savedcnp);
- res_inode = CTOI(savedcnp);
- iget(res_inode->i_sb, res_inode->i_ino);
- CDEBUG(D_INODE, "cache hit for ino: %ld, count: %d!\n",
- res_inode->i_ino, res_inode->i_count);
- goto exit;
- }
- CDEBUG(D_INODE, "name not found in cache!\n");
-
- /* name not cached */
error = venus_lookup(dir->i_sb, &(dircnp->c_fid),
- (const char *)name, length, &type, &resfid);
+ (const char *)name, length, &type, &resfid);
res_inode = NULL;
- if (!error) {
+ if (!error || (error == -CFS_NOCACHE) ) {
+ if (error == -CFS_NOCACHE)
+ dropme = 1;
error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
if (error)
- return -EACCES;
- /* put the thing in the name cache */
- savedcnp = ITOC(res_inode);
- CHECK_CNODE(savedcnp);
- CDEBUG(D_INODE, "ABOUT to enter into cache.\n");
- cfsnc_enter(dircnp, name, length, savedcnp);
- CDEBUG(D_INODE, "entered in cache\n");
+ return -error;
} else if (error != -ENOENT) {
- CDEBUG(D_INODE, "error for %s(%s)%d\n",
- coda_f2s(&dircnp->c_fid, str), name, error);
+ CDEBUG(D_INODE, "error for %s(%*s)%d\n",
+ coda_f2s(&dircnp->c_fid), length, name, error);
return error;
}
- CDEBUG(D_INODE, "lookup: %s is (%s) type %d result %d\n",
- name, coda_f2s(&resfid, str), type, error);
-
- /* at last we have our inode number from Venus,
- now allocate storage for
- the cnode and do iget, and fill in the attributes */
-
+ CDEBUG(D_INODE, "lookup: %s is (%s) type %d result %d, dropme %d\n",
+ name, coda_f2s(&resfid), type, error, dropme);
exit:
entry->d_time = 0;
- entry->d_op = NULL;
+ entry->d_op = &coda_dentry_operations;
d_add(entry, res_inode);
+ if ( dropme )
+ d_drop(entry);
EXIT;
return 0;
}
-
int coda_permission(struct inode *inode, int mask)
{
- struct cnode *cp;
+ struct coda_inode_info *cp;
int error;
- int mode = inode->i_mode;
- char str[50];
ENTRY;
@@ -191,16 +178,10 @@ int coda_permission(struct inode *inode, int mask)
return 0;
}
- /* we should be able to trust what is in the mode
- although Venus should be told to return the
- correct modes to the kernel */
- if ( coda_access_cache == 1 ) {
- if (current->fsuid == inode->i_uid)
- mode >>= 6;
- else if (in_group_p(inode->i_gid))
- mode >>= 3;
- if (((mode & mask & 0007) == mask) )
- return 0;
+ if ( coda_access_cache == 1 ) {
+ if ( coda_cache_check(inode, mask) ) {
+ return 0;
+ }
}
cp = ITOC(inode);
@@ -210,7 +191,11 @@ int coda_permission(struct inode *inode, int mask)
error = venus_access(inode->i_sb, &(cp->c_fid), mask);
CDEBUG(D_INODE, "fid: %s, ino: %ld (mask: %o) error: %d\n",
- coda_f2s(&(cp->c_fid), str), inode->i_ino, mask, error);
+ coda_f2s(&(cp->c_fid)), inode->i_ino, mask, error);
+
+ if ( error == 0 ) {
+ coda_cache_enter(inode, mask);
+ }
return error;
}
@@ -222,7 +207,7 @@ int coda_permission(struct inode *inode, int mask)
static int coda_create(struct inode *dir, struct dentry *de, int mode)
{
int error=0;
- struct cnode *dircnp;
+ struct coda_inode_info *dircnp;
const char *name=de->d_name.name;
int length=de->d_name.len;
struct inode *result = NULL;
@@ -235,13 +220,17 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
printk("coda_create: inode is null or not a directory\n");
return -ENOENT;
}
+
+ if (coda_isroot(dir) && coda_iscontrol(name, length))
+ return -EPERM;
+
dircnp = ITOC(dir);
CHECK_CNODE(dircnp);
if ( length > CFS_MAXNAMLEN ) {
char str[50];
printk("name too long: create, %s(%s)\n",
- coda_f2s(&dircnp->c_fid, str), name);
+ coda_f2s(&dircnp->c_fid), name);
return -ENAMETOOLONG;
}
@@ -251,47 +240,51 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
if ( error ) {
char str[50];
CDEBUG(D_INODE, "create: %s, result %d\n",
- coda_f2s(&newfid, str), error);
+ coda_f2s(&newfid), error);
+ d_drop(de);
return error;
}
error = coda_cnode_make(&result, &newfid, dir->i_sb);
if ( error ) {
+ d_drop(de);
result = NULL;
return error;
}
/* invalidate the directory cnode's attributes */
dircnp->c_flags &= ~C_VATTR;
- cfsnc_zapfid(&(dircnp->c_fid));
-
d_instantiate(de, result);
return 0;
}
static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
{
- struct cnode *dircnp;
+ struct coda_inode_info *dircnp;
struct inode *inode;
struct coda_vattr attr;
const char *name = de->d_name.name;
int len = de->d_name.len;
int error;
struct ViceFid newfid;
- char fidstr[50];
+
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("coda_mkdir: inode is NULL or not a directory\n");
return -ENOENT;
}
- dircnp = ITOC(dir);
- CHECK_CNODE(dircnp);
if ( len > CFS_MAXNAMLEN )
return -ENAMETOOLONG;
+ if (coda_isroot(dir) && coda_iscontrol(name, len))
+ return -EPERM;
+
+ dircnp = ITOC(dir);
+ CHECK_CNODE(dircnp);
+
CDEBUG(D_INODE, "mkdir %s (len %d) in %s, mode %o.\n",
- name, len, coda_f2s(&(dircnp->c_fid), fidstr), mode);
+ name, len, coda_f2s(&(dircnp->c_fid)), mode);
attr.va_mode = mode;
error = venus_mkdir(dir->i_sb, &(dircnp->c_fid),
@@ -299,97 +292,107 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
if ( error ) {
CDEBUG(D_INODE, "mkdir error: %s result %d\n",
- coda_f2s(&newfid, fidstr), error);
+ coda_f2s(&newfid), error);
+ d_drop(de);
return error;
}
CDEBUG(D_INODE, "mkdir: new dir has fid %s.\n",
- coda_f2s(&newfid, fidstr));
+ coda_f2s(&newfid));
error = coda_cnode_make(&inode, &newfid, dir->i_sb);
- if ( error )
- return error;
+ if ( error ) {
+ d_drop(de);
+ return error;
+ }
/* invalidate the directory cnode's attributes */
dircnp->c_flags &= ~C_VATTR;
- cfsnc_zapfid(&(dircnp->c_fid));
-
dir->i_nlink++;
d_instantiate(de, inode);
return 0;
}
-static int coda_link(struct inode *inode, struct inode *dir_inode,
+/* try to make de an entry in dir_inodde linked to source_de */
+static int coda_link(struct dentry *source_de, struct inode *dir_inode,
struct dentry *de)
{
+ struct inode *inode = source_de->d_inode;
const char * name = de->d_name.name;
int len = de->d_name.len;
- struct cnode *dir_cnp, *cnp;
+ struct coda_inode_info *dir_cnp, *cnp;
char str[50];
int error;
ENTRY;
+ if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
+ return -EPERM;
+
dir_cnp = ITOC(dir_inode);
CHECK_CNODE(dir_cnp);
cnp = ITOC(inode);
CHECK_CNODE(cnp);
- CDEBUG(D_INODE, "old: fid: %s\n", coda_f2s(&(cnp->c_fid), str));
- CDEBUG(D_INODE, "directory: %s\n", coda_f2s(&(dir_cnp->c_fid), str));
+ CDEBUG(D_INODE, "old: fid: %s\n", coda_f2s(&(cnp->c_fid)));
+ CDEBUG(D_INODE, "directory: %s\n", coda_f2s(&(dir_cnp->c_fid)));
if ( len > CFS_MAXNAMLEN ) {
printk("coda_link: name too long. \n");
return -ENAMETOOLONG;
}
- /* Check for link to/from control object. */
-
error = venus_link(dir_inode->i_sb,&(cnp->c_fid), &(dir_cnp->c_fid),
(const char *)name, len);
if ( ! error ) {
- dir_cnp->c_flags &= ~C_VATTR;
- cfsnc_zapfid(&(dir_cnp->c_fid));
- cfsnc_zapfid(&(cnp->c_fid));
-
- inode->i_nlink++;
- d_instantiate(de, inode);
+ dir_cnp->c_flags &= ~C_VATTR;
+ inode->i_nlink++;
+ d_instantiate(de, inode);
+ } else {
+ d_drop(de);
}
+
CDEBUG(D_INODE, "link result %d\n",error);
EXIT;
return(error);
}
-static int
-coda_symlink(struct inode *dir_inode, struct dentry *de,
- const char *symname)
+static int coda_symlink(struct inode *dir_inode, struct dentry *de,
+ const char *symname)
{
const char *name = de->d_name.name;
int len = de->d_name.len;
- struct cnode *dir_cnp = ITOC(dir_inode);
+ struct coda_inode_info *dir_cnp = ITOC(dir_inode);
int symlen;
int error=0;
ENTRY;
- error = -ENAMETOOLONG;
- if ( len > CFS_MAXNAMLEN ) {
- return error;
- }
+ if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
+ return -EPERM;
+
+ if ( len > CFS_MAXNAMLEN )
+ return -ENAMETOOLONG;
symlen = strlen(symname);
- if ( symlen > CFS_MAXNAMLEN ) {
- return error;
- }
+ if ( symlen > CFS_MAXPATHLEN )
+ return -ENAMETOOLONG;
+
CDEBUG(D_INODE, "symname: %s, length: %d\n", symname, symlen);
+ /*
+ * This entry is now negative. Since we do not create
+ * an inode for the entry we have to drop it.
+ */
+ d_drop(de);
+
error = venus_symlink(dir_inode->i_sb, &(dir_cnp->c_fid), name, len,
symname, symlen);
if ( !error ) {
- d_drop(de);
+ dir_cnp->c_flags |= C_VATTR;
}
CDEBUG(D_INODE, "in symlink result %d\n",error);
@@ -401,7 +404,7 @@ coda_symlink(struct inode *dir_inode, struct dentry *de,
int coda_unlink(struct inode *dir, struct dentry *de)
{
- struct cnode *dircnp;
+ struct coda_inode_info *dircnp;
int error;
const char *name = de->d_name.name;
int len = de->d_name.len;
@@ -413,10 +416,9 @@ int coda_unlink(struct inode *dir, struct dentry *de)
CHECK_CNODE(dircnp);
CDEBUG(D_INODE, " %s in %s, ino %ld\n", name ,
- coda_f2s(&(dircnp->c_fid), fidstr), dir->i_ino);
+ coda_f2s(&(dircnp->c_fid)), dir->i_ino);
/* this file should no longer be in the namecache! */
- cfsnc_zapfile(dircnp, (const char *)name, len);
error = venus_remove(dir->i_sb, &(dircnp->c_fid), name, len);
@@ -427,7 +429,6 @@ int coda_unlink(struct inode *dir, struct dentry *de)
/* cache management */
dircnp->c_flags &= ~C_VATTR;
- cfsnc_zapfid(&(dircnp->c_fid));
de->d_inode->i_nlink--;
d_delete(de);
@@ -437,10 +438,10 @@ int coda_unlink(struct inode *dir, struct dentry *de)
int coda_rmdir(struct inode *dir, struct dentry *de)
{
- struct cnode *dircnp;
+ struct coda_inode_info *dircnp;
const char *name = de->d_name.name;
int len = de->d_name.len;
- int error;
+ int error, rehash = 0;
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("coda_rmdir: inode is NULL or not a directory\n");
@@ -452,8 +453,24 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
if (len > CFS_MAXNAMLEN)
return -ENAMETOOLONG;
- /* this directory name should no longer be in the namecache */
- cfsnc_zapfile(dircnp, (const char *)name, len);
+ error = -EBUSY;
+ if (de->d_count > 1) {
+ /* Attempt to shrink child dentries ... */
+ shrink_dcache_parent(de);
+ if (de->d_count > 1)
+ return error;
+ }
+ /* Drop the dentry to force a new lookup */
+ if (!list_empty(&de->d_hash)) {
+ d_drop(de);
+ rehash = 1;
+ }
+
+ /* update i_nlink and free the inode before unlinking;
+ if rmdir fails a new lookup set i_nlink right.*/
+ if (de->d_inode->i_nlink)
+ de->d_inode->i_nlink --;
+ d_delete(de);
error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len);
@@ -462,11 +479,9 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
return error;
}
- dircnp->c_flags &= ~C_VATTR;
- cfsnc_zapfid(&(dircnp->c_fid));
-
- dir->i_nlink--;
- d_delete(de);
+ if (rehash)
+ d_add(de, NULL);
+ /* XXX how can mtime be set? */
return 0;
}
@@ -481,7 +496,7 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
int new_length = new_dentry->d_name.len;
struct inode *old_inode = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode;
- struct cnode *new_cnp, *old_cnp;
+ struct coda_inode_info *new_cnp, *old_cnp;
int error, rehash = 0, update = 1;
ENTRY;
old_cnp = ITOC(old_dir);
@@ -496,8 +511,8 @@ ENTRY;
}
/* the old file should go from the namecache */
- cfsnc_zapfile(old_cnp, (const char *)old_name, old_length);
- cfsnc_zapfile(new_cnp, (const char *)new_name, new_length);
+/* cfsnc_zapfile(old_cnp, (const char *)old_name, old_length); */
+/* cfsnc_zapfile(new_cnp, (const char *)new_name, new_length); */
/* cross directory moves */
if (new_dir != old_dir &&
@@ -541,7 +556,7 @@ ENTRY;
int coda_readdir(struct file *file, void *dirent, filldir_t filldir)
{
int result = 0;
- struct cnode *cnp;
+ struct coda_inode_info *cnp;
struct file open_file;
struct dentry open_dentry;
struct inode *inode=file->f_dentry->d_inode;
@@ -581,23 +596,21 @@ int coda_open(struct inode *i, struct file *f)
{
ino_t ino;
dev_t dev;
- struct cnode *cnp;
+ struct coda_inode_info *cnp;
int error = 0;
struct inode *cont_inode = NULL;
unsigned short flags = f->f_flags;
+ unsigned short coda_flags = coda_flags_to_cflags(flags);
ENTRY;
CDEBUG(D_SPECIAL, "OPEN inode number: %ld, flags %o.\n",
f->f_dentry->d_inode->i_ino, flags);
- if ( flags & O_CREAT ) {
- flags &= ~O_EXCL; /* taken care of by coda_create ?? */
- }
cnp = ITOC(i);
CHECK_CNODE(cnp);
- error = venus_open(i->i_sb, &(cnp->c_fid), flags, &ino, &dev);
+ error = venus_open(i->i_sb, &(cnp->c_fid), coda_flags, &ino, &dev);
if (error) {
CDEBUG(D_FILE, "venus: dev %d, inode %ld, out->result %d\n",
dev, ino, error);
@@ -618,14 +631,13 @@ int coda_open(struct inode *i, struct file *f)
CDEBUG(D_FILE, "GRAB: coda_inode_grab: ino %ld, ops at %x\n",
cont_inode->i_ino, (int)cont_inode->i_op);
cnp->c_ovp = cont_inode;
- cnp->c_odentry.d_inode = cont_inode;
}
cnp->c_ocount++;
/* if opened for writing flush cache entry. */
- if ( flags & (O_WRONLY | O_RDWR) ) {
- cfsnc_zapfid(&(cnp->c_fid));
- }
+/* if ( flags & (O_WRONLY | O_RDWR) ) { */
+/* cfsnc_zapfid(&(cnp->c_fid)); */
+/* } */
CDEBUG(D_FILE, "result %d, coda i->i_count is %d for ino %ld\n",
error, i->i_count, i->i_ino);
@@ -638,9 +650,10 @@ int coda_open(struct inode *i, struct file *f)
int coda_release(struct inode *i, struct file *f)
{
- struct cnode *cnp;
+ struct coda_inode_info *cnp;
int error;
unsigned short flags = f->f_flags;
+ unsigned short cflags = coda_flags_to_cflags(flags);
ENTRY;
@@ -664,7 +677,7 @@ int coda_release(struct inode *i, struct file *f)
--cnp->c_owrite;
}
- error = venus_release(i->i_sb, &(cnp->c_fid), flags);
+ error = venus_release(i->i_sb, &(cnp->c_fid), cflags);
CDEBUG(D_FILE, "coda_release: result: %d\n", error);
return error;
@@ -693,6 +706,7 @@ static int coda_venus_readdir(struct file *filp, void *getdent,
struct venus_dirent *vdirent;
struct getdents_callback *dents_callback;
int string_offset;
+ int size;
char debug[255];
ENTRY;
@@ -703,8 +717,8 @@ static int coda_venus_readdir(struct file *filp, void *getdent,
dents_callback = (struct getdents_callback *) getdent;
- count = dents_callback->count;
- CODA_ALLOC(buff, void *, count);
+ size = count = dents_callback->count;
+ CODA_ALLOC(buff, void *, size);
if ( ! buff ) {
printk("coda_venus_readdir: out of memory.\n");
return -ENOMEM;
@@ -764,6 +778,6 @@ CDEBUG(D_FILE, "ino %ld, namlen %d, reclen %d, type %d, pos %d, string_offs %d,
}
exit:
- CODA_FREE(buff, count);
+ CODA_FREE(buff, size);
return error;
}
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 225ca881a..b33680cc3 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -18,19 +18,21 @@
#include <linux/string.h>
#include <asm/uaccess.h>
-#include <linux/coda_namecache.h>
#include <linux/coda.h>
#include <linux/coda_linux.h>
-#include <linux/coda_cnode.h>
+#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
+#include <linux/coda_cache.h>
/* file operations */
-static int coda_readpage(struct inode * inode, struct page * page);
+static int coda_readpage(struct file *file, struct page * page);
static ssize_t coda_file_read(struct file *f, char *buf, size_t count, loff_t *off);
static ssize_t coda_file_write(struct file *f, const char *buf, size_t count, loff_t *off);
static int coda_file_mmap(struct file * file, struct vm_area_struct * vma);
/* exported from this file */
+int coda_fsync(struct file *, struct dentry *dentry);
+
struct inode_operations coda_file_inode_operations = {
&coda_file_operations, /* default file operations */
NULL, /* create */
@@ -64,14 +66,21 @@ struct file_operations coda_file_operations = {
coda_file_mmap, /* mmap */
coda_open, /* open */
coda_release, /* release */
- NULL, /* fsync */
+ coda_fsync, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
};
/* File file operations */
-static int coda_readpage(struct inode * inode, struct page * page)
+static int coda_readpage(struct file * file, struct page * page)
{
- struct inode *open_inode;
- struct cnode *cnp;
+ struct dentry *de = file->f_dentry;
+ struct inode *inode = de->d_inode;
+ struct dentry cont_dentry;
+ struct inode *cont_inode;
+ struct coda_inode_info *cnp;
ENTRY;
@@ -83,18 +92,19 @@ static int coda_readpage(struct inode * inode, struct page * page)
return -ENXIO;
}
- open_inode = cnp->c_ovp;
+ cont_inode = cnp->c_ovp;
+ cont_dentry.d_inode = cont_inode;
- CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", inode->i_ino, open_inode->i_ino, page->offset);
+ CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", inode->i_ino, cont_inode->i_ino, page->offset);
- generic_readpage(open_inode, page);
+ generic_readpage(&cont_dentry, page);
EXIT;
return 0;
}
static int coda_file_mmap(struct file * file, struct vm_area_struct * vma)
{
- struct cnode *cnp;
+ struct coda_inode_info *cnp;
cnp = ITOC(file->f_dentry->d_inode);
cnp->c_mmcount++;
@@ -104,7 +114,7 @@ static int coda_file_mmap(struct file * file, struct vm_area_struct * vma)
static ssize_t coda_file_read(struct file *coda_file, char *buff,
size_t count, loff_t *ppos)
{
- struct cnode *cnp;
+ struct coda_inode_info *cnp;
struct inode *coda_inode = coda_file->f_dentry->d_inode;
struct inode *cont_inode = NULL;
struct file cont_file;
@@ -144,7 +154,7 @@ static ssize_t coda_file_read(struct file *coda_file, char *buff,
static ssize_t coda_file_write(struct file *coda_file, const char *buff,
size_t count, loff_t *ppos)
{
- struct cnode *cnp;
+ struct coda_inode_info *cnp;
struct inode *coda_inode = coda_file->f_dentry->d_inode;
struct inode *cont_inode = NULL;
struct file cont_file;
@@ -181,8 +191,44 @@ static ssize_t coda_file_write(struct file *coda_file, const char *buff,
return result;
}
+int coda_fsync(struct file *coda_file, struct dentry *coda_dentry)
+{
+ struct coda_inode_info *cnp;
+ struct inode *coda_inode = coda_dentry->d_inode;
+ struct inode *cont_inode = NULL;
+ struct file cont_file;
+ struct dentry cont_dentry;
+ int result = 0;
+ ENTRY;
+
+ if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
+ S_ISLNK(coda_inode->i_mode)))
+ return -EINVAL;
+ cnp = ITOC(coda_inode);
+ CHECK_CNODE(cnp);
+ cont_inode = cnp->c_ovp;
+ if ( cont_inode == NULL ) {
+ printk("coda_file_write: cached inode is 0!\n");
+ return -1;
+ }
+
+ coda_prepare_openfile(coda_inode, coda_file, cont_inode,
+ &cont_file, &cont_dentry);
+
+ down(&cont_inode->i_sem);
+
+ result = file_fsync(&cont_file ,&cont_dentry);
+ if ( result == 0 ) {
+ result = venus_fsync(coda_inode->i_sb, &(cnp->c_fid));
+ }
+
+ up(&cont_inode->i_sem);
+
+ coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
+ return result;
+}
/*
* support routines
*/
@@ -209,7 +255,7 @@ void coda_restore_codafile(struct inode *coda_inode, struct file *coda_file,
{
coda_file->f_pos = open_file->f_pos;
/* XXX what about setting the mtime here too? */
- coda_inode->i_mtime = open_inode->i_mtime;
+ /* coda_inode->i_mtime = open_inode->i_mtime; */
coda_inode->i_size = open_inode->i_size;
return;
}
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
deleted file mode 100644
index b295470fa..000000000
--- a/fs/coda/inode.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Inode operations for Coda filesystem
- * Original version: (C) 1996 P. Braam and M. Callahan
- * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
- *
- * Carnegie Mellon encourages users to contribute improvements to
- * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/locks.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-#include <linux/string.h>
-
-#include <linux/coda.h>
-#include <linux/coda_linux.h>
-#include <linux/coda_psdev.h>
-#include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
-
-/* prototypes */
-static int coda_readpage(struct inode *inode, struct page *page);
-static int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
-
-
-
-
-
diff --git a/fs/coda/namecache.c b/fs/coda/namecache.c
deleted file mode 100644
index 08f1ee9e7..000000000
--- a/fs/coda/namecache.c
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
- * Cache operations for Coda.
- * Original version: (C) 1996 Peter Braam
- * Rewritten for Linux 2.1: (C) 1997 Carnegie Mellon University
- *
- * Carnegie Mellon encourages users of this code to contribute improvements
- * to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
- */
-
-/*
- * This module contains the routines to implement the CFS name cache. The
- * purpose of this cache is to reduce the cost of translating pathnames
- * into Vice FIDs. Each entry in the cache contains the name of the file,
- * the vnode (FID) of the parent directory, and the cred structure of the
- * user accessing the file.
- *
- * The first time a file is accessed, it is looked up by the local Venus
- * which first insures that the user has access to the file. In addition
- * we are guaranteed that Venus will invalidate any name cache entries in
- * case the user no longer should be able to access the file. For these
- * reasons we do not need to keep access list information as well as a
- * cred structure for each entry.
- *
- * The table can be accessed through the routines cnc_init(), cnc_enter(),
- * cnc_lookup(), cnc_rmfidcred(), cnc_rmfid(), cnc_rmcred(), and cnc_purge().
- * There are several other routines which aid in the implementation of the
- * hash table.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/locks.h>
-#include <asm/segment.h>
-#include <linux/string.h>
-
-#include <linux/coda.h>
-#include <linux/coda_linux.h>
-#include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
-
-int cfsnc_use;
-
-static struct cfscache * cfsnc_find(struct cnode *dcp, const char * name, int namelen, int hash);
-static void cfsnc_remove(struct cfscache *cncp);
-static inline int nchash(const char *, int, struct cnode *);
-static inline int ncmatch(struct cfscache *, const char *, int,
- struct cnode *);
-static inline void hashins(struct cfscache *a, struct cfscache *pred);
-static inline void hashrem(struct cfscache *a);
-static inline void hashnull(struct cfscache *);
-static inline void lrurem(struct cfscache *a);
-static inline void lruins(struct cfscache *a, struct cfscache *pred);
-static void cfsnc_gather_stats(void);
-
-
-/* externals */
-extern int coda_fideq(ViceFid *fid1, ViceFid *fid2);
-extern int coda_debug;
-extern int coda_print_entry;
-extern struct super_block *coda_super_block;
-
-
-
-/*
- * Declaration of the name cache data structure.
- */
-
-int cfsnc_use = 0; /* Indicate use of CFS Name Cache */
-int cfsnc_size = CFSNC_CACHESIZE; /* size of the cache */
-int cfsnc_hashsize = CFSNC_HASHSIZE; /* size of the primary hash */
-int cfsnc_flushme = 0;
-int cfsnc_procsize = 0;
-static int cfsnc_force = 0;
-
-struct cfshash {
- struct cfscache *hash_next, *hash_prev;
- int length;
-};
-
-struct cfslruhead {
- struct cfscache *dummy1, *dummy2;
- struct cfscache *lru_next, *lru_prev;
-};
-
-struct cfscache *cfsncheap; /* pointer to the cache entries */
-struct cfshash *cfsnchash; /* hash table of cfscache pointers */
-struct cfslruhead cfsnc_lru; /* head of lru chain; prev = lru */
-
-struct cfsnc_statistics cfsnc_stat; /* Keep various stats */
-
-#define TOTAL_CACHE_SIZE (sizeof(struct cfscache) * cfsnc_size)
-#define TOTAL_HASH_SIZE (sizeof(struct cfshash) * cfsnc_hashsize)
-int cfsnc_initialized = 0; /* Initially the cache has not been initialized */
-
-/*
- * for testing purposes
- */
-int cfsnc_debug = 1;
-
-
-/*
- * Auxillary routines -- shouldn't be entry points
- */
-
-
-/*
- * Hash function for the primary hash.
- * First try -- (first + last letters + length + (int)cp) mod size
- * 2nd try -- same, except dir fid.vnode instead of cp
- */
-static inline int
-nchash(const char *name, int namelen, struct cnode *cp)
-{
- return ((name[0] + name[namelen-1] +
- namelen + (int)(cp)) & (cfsnc_hashsize-1));
-}
-
-/* matching function */
-static inline int ncmatch(struct cfscache *cp, const char *name, int namelen,
- struct cnode *dcp)
-{
- return ((namelen == cp->namelen) && (dcp == cp->dcp) &&
- (memcmp(cp->name,name,namelen) == 0));
-}
-
-/* insert a behind pred */
-static inline void hashins(struct cfscache *a, struct cfscache *pred)
-{
- a->hash_next = pred->hash_next;
- pred->hash_next->hash_prev= a;
- pred->hash_next = a;
- a->hash_prev = pred;
-}
-
-static inline void hashrem(struct cfscache *a)
-{
- a->hash_prev->hash_next = a->hash_next;
- a->hash_next->hash_prev = a->hash_prev;
-}
-
-static inline void hashnull(struct cfscache *elem) {
- elem->hash_next = elem;
- elem->hash_prev = elem;
-}
-
-static inline void lrurem(struct cfscache *a)
-{
- a->lru_prev->lru_next = a->lru_next;
- a->lru_next->lru_prev = a->lru_prev;
-}
-
-static inline void lruins(struct cfscache *a, struct cfscache *pred)
-{
- pred->lru_next->lru_prev= a;
- a->lru_next = pred->lru_next;
-
- a->lru_prev = pred;
- pred->lru_next = a;
-}
-
-static struct cfscache *
-cfsnc_find(struct cnode *dcp, const char * name, int namelen, int hash)
-{
- /*
- * hash to find the appropriate bucket, look through the chain
- * for the right entry
- */
- register struct cfscache *cncp;
- int count = 1;
-
- CDEBUG(D_CACHE, "dcp 0x%x, name %s, len %d, hash %d\n",
- (int)dcp, name, namelen, hash);
-
- for (cncp = cfsnchash[hash].hash_next;
- cncp != (struct cfscache *)&cfsnchash[hash];
- cncp = cncp->hash_next, count++)
- {
-
- if (ncmatch(cncp, name, namelen, dcp))
- {
- cfsnc_stat.Search_len += count;
- CDEBUG(D_CACHE, "dcp 0x%x,found.\n", (int) dcp);
- return(cncp);
-
- }
- }
- CDEBUG(D_CACHE, "dcp 0x%x,not found.\n", (int) dcp);
- return((struct cfscache *)0);
-}
-
-static void
-cfsnc_remove(struct cfscache *cncp)
-{
- /*
- * remove an entry -- VN_RELE(cncp->dcp, cp), crfree(cred),
- * remove it from it's hash chain, and
- * place it at the head of the lru list.
- */
- CDEBUG(D_CACHE, "remove %s from parent %lx.%lx.%lx\n",
- cncp->name, (cncp->dcp)->c_fid.Volume,
- (cncp->dcp)->c_fid.Vnode, (cncp->dcp)->c_fid.Unique);
-
- hashrem(cncp);
- hashnull(cncp); /* have it be a null chain */
-
- /* VN_RELE(CTOV(cncp->dcp)); */
- iput(CTOI(cncp->cp));
- /* crfree(cncp->cred); */
-
- memset(DATA_PART(cncp), 0 ,DATA_SIZE);
- cncp->cp = NULL;
- cncp->dcp = (struct cnode *) 0;
-
- /* Put the null entry just after the least-recently-used entry */
- lrurem(cncp);
- lruins(cncp, cfsnc_lru.lru_prev);
-}
-
-
-/*
- * Entry points for the CFS Name Cache
- */
-
-/*
- * Initialize the cache, the LRU structure and the Hash structure(s)
- */
-void
-cfsnc_init(void)
-{
- register int i;
-
- /* zero the statistics structure */
- cfsnc_procsize = 10000 * cfsnc_hashsize + cfsnc_size;
- memset(&cfsnc_stat, 0, (sizeof(struct cfsnc_statistics)));
-
- CODA_ALLOC(cfsncheap, struct cfscache *, TOTAL_CACHE_SIZE);
- CODA_ALLOC(cfsnchash, struct cfshash *, TOTAL_HASH_SIZE);
-
- cfsnc_lru.lru_next = cfsnc_lru.lru_prev = (struct cfscache *)&cfsnc_lru;
-
- /* initialize the heap */
- for (i=0; i < cfsnc_size; i++) {
- lruins(&cfsncheap[i], (struct cfscache *) &cfsnc_lru);
- hashnull(&cfsncheap[i]);
- cfsncheap[i].cp = cfsncheap[i].dcp = (struct cnode *)0;
- }
-
- for (i=0; i < cfsnc_hashsize; i++) { /* initialize the hashtable */
- hashnull((struct cfscache *)&cfsnchash[i]);
- cfsnchash[i].length=0; /* bucket length */
- }
-
- cfsnc_initialized = 1;
- CDEBUG(D_CACHE, "cfsnc_initialized is now 1.\n");
-}
-
-/*
- * Enter a new (dir cnode, name) pair into the cache, updating the
- * LRU and Hash as needed.
- */
-
-void
-cfsnc_enter(struct cnode *dcp, register const char *name, int namelen, struct cnode *cp)
-{
- register struct cfscache *cncp;
- register int hash;
-
- if (cfsnc_use == 0) /* Cache is off */
- return;
-
- CDEBUG(D_CACHE, "dcp 0x%x cp 0x%x name %s, ind 0x%x \n",
- (int)dcp, (int)cp, name, (int)cp->c_vnode);
-
- if (namelen > CFSNC_NAMELEN) {
- CDEBUG(D_CACHE, "long name enter %s\n",name);
- cfsnc_stat.long_name_enters++; /* record stats */
- return;
- }
-
- hash = nchash(name, namelen, dcp);
- CDEBUG(D_CACHE, "Calling find with name %s, dcp %d, hash %d\n",
- name, (int) dcp, (int) hash);
-
- cncp = cfsnc_find(dcp, name, namelen, hash);
- if (cncp != (struct cfscache *) 0) {
- printk("cfsnc_enter: Duplicate cache entry; tell Peter.\n");
- cfsnc_stat.dbl_enters++; /* duplicate entry */
- return;
- }
-
- cfsnc_stat.enters++; /* record the enters statistic */
-
- /* Grab the lru element in the lru chain */
- cncp = cfsnc_lru.lru_prev;
-
- lrurem(cncp); /* remove it from the lists */
-
- /* if cncp is on hash list remove it */
- if ( cncp->dcp != (struct cnode *) 0 ) {
- /* We have to decrement the appropriate hash bucket length
- here, so we have to find the hash bucket */
- cfsnchash[nchash(cncp->name, cncp->namelen, cncp->dcp)].length--;
- cfsnc_stat.lru_rm++; /* zapped a valid entry */
- hashrem(cncp);
- iput(CTOI(cncp->cp));
- /* VN_RELE(CTOV(cncp->dcp)); */
- /* crfree(cncp->cred); */
- }
- /*
- * Put a hold on the current vnodes and fill in the cache entry.
- */
- iget((CTOI(cp))->i_sb, CTOI(cp)->i_ino);
- /* VN_HOLD(CTOV(dcp)); */
- /* XXXX crhold(cred); */
- cncp->dcp = dcp;
- cncp->cp = cp;
- cncp->namelen = namelen;
- /* cncp->cred = cred; */
-
- memcpy(cncp->name, name, (unsigned)namelen);
-
- /* Insert into the lru and hash chains. */
-
- lruins(cncp, (struct cfscache *) &cfsnc_lru);
- hashins(cncp, (struct cfscache *)&cfsnchash[hash]);
- cfsnchash[hash].length++; /* Used for tuning */
- CDEBUG(D_CACHE, "Entering:\n");
- coda_print_ce(cncp);
-}
-
-/*
- * Find the (dir cnode, name) pair in the cache, if it's cred
- * matches the input, return it, otherwise return 0
- */
-
-struct cnode *
-cfsnc_lookup(struct cnode *dcp, register const char *name, int namelen)
-{
- register int hash;
- register struct cfscache *cncp;
- /* this should go into a callback funcntion for /proc/sys
- don't know how at the moment? */
- if (cfsnc_flushme == 1) {
- cfsnc_flush();
- cfsnc_flushme = 0;
- }
-
- if (cfsnc_procsize != 10000*cfsnc_hashsize + cfsnc_size ) {
- int hsh = cfsnc_procsize/10000;
- int siz = cfsnc_procsize%10000;
- int rc;
-
- if ( (hsh > 1) && (siz > 2) ) {
- rc = cfsnc_resize(hsh, siz);
- if ( !rc ) {
- printk("Coda:cache size (hash,size) (%d,%d)\n",
- hsh, siz);
- } else {
- printk("Coda: cache resize failed\n");
- }
- }
- }
-
- if (cfsnc_use == 0) /* Cache is off */
- return((struct cnode *) 0);
-
- if (namelen > CFSNC_NAMELEN) {
- CDEBUG(D_CACHE,"long name lookup %s\n",name);
- cfsnc_stat.long_name_lookups++; /* record stats */
- return((struct cnode *) 0);
- }
-
- /* Use the hash function to locate the starting point,
- then the search routine to go down the list looking for
- the correct cred.
- */
-
- hash = nchash(name, namelen, dcp);
- CDEBUG(D_CACHE, "Calling find with name %s, dcp %d, hash %d\n",
- name, (int) dcp, (int) hash);
- cncp = cfsnc_find(dcp, name, namelen, hash);
- if (cncp == (struct cfscache *) 0) {
- cfsnc_stat.misses++; /* record miss */
- return((struct cnode *) 0);
- }
-
- cfsnc_stat.hits++;
-
- /* put this entry at the mru end of the LRU */
- lrurem(cncp);
- lruins(cncp, (struct cfscache *) &cfsnc_lru);
-
- /* move it to the front of the hash chain */
- /* don't need to change the hash bucket length */
- hashrem(cncp);
- hashins(cncp, (struct cfscache *) &cfsnchash[hash]);
-
- CDEBUG(D_CACHE, "lookup: dcp 0x%x, name %s, cp 0x%x\n",
- (int) dcp, name, (int) cncp->cp);
-
- return(cncp->cp);
-}
-
-/*
- * Remove all entries with a parent which has the input fid.
- */
-
-void
-cfsnc_zapParentfid(ViceFid *fid)
-{
- /* To get to a specific fid, we might either have another hashing
- function or do a sequential search through the cache for the
- appropriate entries. The later may be acceptable since I don't
- think callbacks or whatever Case 1 covers are frequent occurences.
- */
- register struct cfscache *cncp, *ncncp;
- register int i;
-
- if (cfsnc_use == 0) /* Cache is off */
- return;
-
- CDEBUG(D_CACHE, " fid 0x%lx, 0x%lx, 0x%lx \n",
- fid->Volume, fid->Vnode, fid->Unique);
-
- cfsnc_stat.zapPfids++;
-
- for (i = 0; i < cfsnc_hashsize; i++) {
-
- /*
- * Need to save the hash_next pointer in case we remove the
- * entry. remove causes hash_next to point to itself.
- */
-
- for (cncp = cfsnchash[i].hash_next;
- cncp != (struct cfscache *) &cfsnchash[i];
- cncp = ncncp) {
- ncncp = cncp->hash_next;
- if ( coda_fideq(&cncp->dcp->c_fid, fid) ) {
- cfsnchash[i].length--; /* Used for tuning */
- cfsnc_remove(cncp);
- }
- }
- }
-}
-
-/*
- * Remove all entries which have the same fid as the input
- */
-void
-cfsnc_zapfid(ViceFid *fid)
-{
- /* See comment for zapParentfid. This routine will be used
- if attributes are being cached.
- */
- register struct cfscache *cncp, *ncncp;
- register int i;
-
- if (cfsnc_use == 0) /* Cache is off */
- return;
-
- CDEBUG(D_CACHE, "Zapfid: fid 0x%lx, 0x%lx, 0x%lx \n",
- fid->Volume, fid->Vnode, fid->Unique);
-
- cfsnc_stat.zapFids++;
-
- for (i = 0; i < cfsnc_hashsize; i++) {
- for (cncp = cfsnchash[i].hash_next;
- cncp != (struct cfscache *) &cfsnchash[i];
- cncp = ncncp) {
- ncncp = cncp->hash_next;
- if (coda_fideq(&(cncp->cp->c_fid), fid)) {
- CDEBUG(D_CACHE, "Found cncp: name %s\n", cncp->name);
- cfsnchash[i].length--; /* Used for tuning */
- cfsnc_remove(cncp);
- }
- }
- }
-}
-
-
-/*
- * Remove all entries which have the (dir vnode, name) pair
- */
-void
-cfsnc_zapfile(struct cnode *dcp, register const char *name, int length)
-{
- /* use the hash function to locate the file, then zap all
- entries of it regardless of the cred.
- */
- register struct cfscache *cncp;
- int hash;
-
- if (cfsnc_use == 0) /* Cache is off */
- return;
-
- CDEBUG(D_CACHE,"Zapfile: dcp 0x%x name %s \n",
- (int) dcp, name);
-
- if (length > CFSNC_NAMELEN) {
- cfsnc_stat.long_remove++; /* record stats */
- return;
- }
-
- cfsnc_stat.zapFile++;
-
- hash = nchash(name, length, dcp);
- /* remove entries: remember they might exist for more than a
- single cred */
- while ( (cncp = cfsnc_find(dcp, name, length, hash)) != NULL ) {
- cfsnchash[hash].length--;
- cfsnc_remove(cncp);
- }
-}
-
-/*
- * Remove all the entries for a particular user. Used when tokens expire.
- * A user is determined by his/her effective user id (id_uid).
- */
-
-void
-cfsnc_purge_user(struct CodaCred *cred)
-{
- /* I think the best approach is to go through the entire cache
- via HASH or whatever and zap all entries which match the
- input cred. Or just flush the whole cache.
- It might be best to go through on basis of LRU since cache
- will almost always be full and LRU is more straightforward.
- */
-
- register struct cfscache *cncp;
- int hash;
-
- if (cfsnc_use == 0) /* Cache is off */
- return;
-
- CDEBUG(D_CACHE,"ZapDude: uid %ld\n",cred->cr_uid);
- cfsnc_stat.zapUsers++;
-
- for (cncp = cfsnc_lru.lru_next;
- cncp != (struct cfscache *) &cfsnc_lru;
- cncp = cncp->lru_next) {
-
- if ((CFSNC_VALID(cncp)) &&
- ((cncp->cred)->cr_uid == cred->cr_uid)) {
- /* Seems really ugly, but we have to decrement the appropriate
- hash bucket length here, so we have to find the hash bucket
- */
- hash = nchash(cncp->name, cncp->namelen, cncp->dcp);
- cfsnchash[hash].length--; /* For performance tuning */
-
- cfsnc_remove(cncp);
- }
- }
-}
-
-/*
- * Flush the entire name cache. In response to a flush of the Venus cache.
- */
-
-void
-cfsnc_flush(void)
-{
- /* One option is to deallocate the current name cache and
- call init to start again. Or just deallocate, then rebuild.
- Or again, we could just go through the array and zero the
- appropriate fields.
- */
-
- /*
- * Go through the whole lru chain and kill everything as we go.
- * I don't use remove since that would rebuild the lru chain
- * as it went and that seemed unneccesary.
- */
- register struct cfscache *cncp;
- int i;
-
- if ((cfsnc_use == 0 || cfsnc_initialized == 0) && (cfsnc_force == 0) )
- return;
-
- cfsnc_stat.Flushes++;
-
- for (cncp = cfsnc_lru.lru_next;
- cncp != (struct cfscache *) &cfsnc_lru;
- cncp = cncp->lru_next) {
- if ( cncp->cp ) {
- hashrem(cncp); /* only zero valid nodes */
- hashnull(cncp);
- iput(CTOI(cncp->cp));
- /* crfree(cncp->cred); */
- memset(DATA_PART(cncp), 0, DATA_SIZE);
- }
- }
-
- for (i = 0; i < cfsnc_hashsize; i++)
- cfsnchash[i].length = 0;
-}
-
-/*
- * This routine replaces a ViceFid in the name cache with another.
- * It is added to allow Venus during reintegration to replace
- * locally allocated temp fids while disconnected with global fids
- * even when the reference count on those fids are not zero.
- */
-void
-cfsnc_replace(ViceFid *f1, ViceFid *f2)
-{
- /*
- * Replace f1 with f2 throughout the name cache
- */
- int hash;
- register struct cfscache *cncp;
-
- CDEBUG(D_CACHE,
- "cfsnc_replace fid_1 = (%lx.%lx.%lx) and fid_2 = (%lx.%lx.%lx)\n",
- f1->Volume, f1->Vnode, f1->Unique,
- f2->Volume, f2->Vnode, f2->Unique);
-
- for (hash = 0; hash < cfsnc_hashsize; hash++) {
- for (cncp = cfsnchash[hash].hash_next;
- cncp != (struct cfscache *) &cfsnchash[hash];
- cncp = cncp->hash_next) {
- if (!memcmp(&cncp->cp->c_fid, f1, sizeof(ViceFid))) {
- memcpy(&cncp->cp->c_fid, f2, sizeof(ViceFid));
- continue; /* no need to check cncp->dcp now */
- }
- if (!memcmp(&cncp->dcp->c_fid, f1, sizeof(ViceFid)))
- memcpy(&cncp->dcp->c_fid, f2, sizeof(ViceFid));
- }
- }
-}
-
-/*
- * Debugging routines
- */
-
-/*
- * This routine should print out all the hash chains to the console.
- */
-
-void
-print_cfsnc(void)
-{
- int hash;
- register struct cfscache *cncp;
-
- for (hash = 0; hash < cfsnc_hashsize; hash++) {
- printk("\nhash %d\n",hash);
-
- for (cncp = cfsnchash[hash].hash_next;
- cncp != (struct cfscache *)&cfsnchash[hash];
- cncp = cncp->hash_next) {
- printk("cp 0x%x dcp 0x%x cred 0x%x name %s ino %d count %d dev %d\n",
- (int)cncp->cp, (int)cncp->dcp,
- (int)cncp->cred, cncp->name, CTOI(cncp->cp)->i_count, CTOI(cncp->cp)->i_count, CTOI(cncp->cp)->i_dev);
- }
- }
-}
-
-int
-cfsnc_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
-{
- int hash;
- int len=0;
- off_t pos=0;
- off_t begin;
- struct cfscache *cncp;
- char tmpbuf[80];
-
- if (offset < 80)
- len += sprintf(buffer, "%-79s\n",
- "hash len volume vnode unique name ino pino ct");
- if ( !cfsnc_initialized ) {
- *start = buffer;
- return len;
- }
- pos = 80;
- for (hash = 0; hash < cfsnc_hashsize; hash++) {
- for (cncp = cfsnchash[hash].hash_next;
- cncp != (struct cfscache *)&cfsnchash[hash];
- cncp = cncp->hash_next) {
- pos += 80;
- if (pos < offset)
- continue;
- sprintf(tmpbuf, "%4d %3d %8x %8x %8x %16s %10ld %10ld %2d",
- hash, cfsnchash[hash].length, (int) cncp->cp->c_fid.Volume,
- (int) cncp->cp->c_fid.Vnode, (int) cncp->cp->c_fid.Unique , cncp->name,
- CTOI(cncp->cp)->i_ino,
- CTOI(cncp->dcp)->i_ino,
- CTOI(cncp->cp)->i_count);
- len += sprintf(buffer+len, "%-79s\n", tmpbuf);
- if(len >= length)
- break;
- }
- if(len>= length)
- break;
- }
- begin = len - (pos - offset);
- *start = buffer + begin;
- len -= begin;
- if(len>length)
- len = length;
- return len;
-}
-
-int
-cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy)
-{
- int len=0;
- off_t begin;
-
- cfsnc_gather_stats();
-
- /* this works as long as we are below 1024 characters! */
- len += sprintf(buffer,"Coda minicache statistics\n\n");
- len += sprintf(buffer+len, "cfsnc_hits : %d\n", cfsnc_stat.hits);
- len += sprintf(buffer+len, "cfsnc_misses : %d\n", cfsnc_stat.misses);
- len += sprintf(buffer+len, "cfsnc_enters : %d\n", cfsnc_stat.enters);
- len += sprintf(buffer+len, "cfsnc_dbl_enters : %d\n", cfsnc_stat.dbl_enters);
- len += sprintf(buffer+len, "cfsnc_long_name_enters : %d\n", cfsnc_stat.long_name_enters);
- len += sprintf(buffer+len, "cfsnc_long_name_lookups : %d\n", cfsnc_stat.long_name_lookups);
- len += sprintf(buffer+len, "cfsnc_long_remove : %d\n", cfsnc_stat.long_remove);
- len += sprintf(buffer+len, "cfsnc_lru_rm : %d\n", cfsnc_stat.lru_rm);
- len += sprintf(buffer+len, "cfsnc_zapPfids : %d\n", cfsnc_stat.zapPfids);
- len += sprintf(buffer+len, "cfsnc_zapFids : %d\n", cfsnc_stat.zapFids);
- len += sprintf(buffer+len, "cfsnc_zapFile : %d\n", cfsnc_stat.zapFile);
- len += sprintf(buffer+len, "cfsnc_zapUsers : %d\n", cfsnc_stat.zapUsers);
- len += sprintf(buffer+len, "cfsnc_Flushes : %d\n", cfsnc_stat.Flushes);
- len += sprintf(buffer+len, "cfsnc_SumLen : %d\n", cfsnc_stat.Sum_bucket_len);
- len += sprintf(buffer+len, "cfsnc_Sum2Len : %d\n", cfsnc_stat.Sum2_bucket_len);
- len += sprintf(buffer+len, "cfsnc_# 0 len : %d\n", cfsnc_stat.Num_zero_len);
- len += sprintf(buffer+len, "cfsnc_MaxLen : %d\n", cfsnc_stat.Max_bucket_len);
- len += sprintf(buffer+len, "cfsnc_SearchLen : %d\n", cfsnc_stat.Search_len);
- begin = offset;
- *start = buffer + begin;
- len -= begin;
-
- if(len>length)
- len = length;
- if (len< 0)
- len = 0;
- return len;
-}
-
-
-
-void
-coda_print_ce(struct cfscache *ce)
-{
-CDEBUG(D_CACHE, "cp 0x%x, dcp 0x%x, name %s, inod 0x%x, ino %d, count %d, dev %d\n",
- (int)ce->cp, (int)ce->dcp, ce->name, (int)CTOI(ce->cp),(int)CTOI(ce->cp)->i_ino, CTOI(ce->cp)->i_count, CTOI(ce->cp)->i_dev);
-}
-
-static void
-cfsnc_gather_stats(void)
-{
- int i, max = 0, sum = 0, temp, zeros = 0, ave, n;
-
- for (i = 0; i < cfsnc_hashsize; i++) {
- if (cfsnchash[i].length) {
- sum += cfsnchash[i].length;
- } else {
- zeros++;
- }
-
- if (cfsnchash[i].length > max)
- max = cfsnchash[i].length;
- }
-
-/*
- * When computing the Arithmetic mean, only count slots which
- * are not empty in the distribution.
- */
- cfsnc_stat.Sum_bucket_len = sum;
- cfsnc_stat.Num_zero_len = zeros;
- cfsnc_stat.Max_bucket_len = max;
-
- if ((n = cfsnc_hashsize - zeros) > 0)
- ave = sum / n;
- else
- ave = 0;
-
- sum = 0;
- for (i = 0; i < cfsnc_hashsize; i++) {
- if (cfsnchash[i].length) {
- temp = cfsnchash[i].length - ave;
- sum += temp * temp;
- }
- }
- cfsnc_stat.Sum2_bucket_len = sum;
-}
-
-/*
- * The purpose of this routine is to allow the hash and cache sizes to be
- * changed dynamically. This should only be used in controlled environments,
- * it makes no effort to lock other users from accessing the cache while it
- * is in an improper state (except by turning the cache off).
- */
-int
-cfsnc_resize(int hashsize, int heapsize)
-{
- if ( !cfsnc_use )
- return 0;
-
- if ((hashsize % 2) || (heapsize % 2)) { /* Illegal hash or cache sizes */
- return(EINVAL);
- }
-
- cfsnc_use = 0; /* Turn the cache off */
- cfsnc_force = 1; /* otherwise we can't flush */
-
- cfsnc_flush(); /* free any cnodes in the cache */
- cfsnc_force = 0;
-
- /* WARNING: free must happen *before* size is reset */
- CODA_FREE(cfsncheap,TOTAL_CACHE_SIZE);
- CODA_FREE(cfsnchash,TOTAL_HASH_SIZE);
-
- cfsnc_hashsize = hashsize;
- cfsnc_size = heapsize;
-
- cfsnc_init(); /* Set up a cache with the new size */
-
- cfsnc_use = 1; /* Turn the cache back on */
- return(0);
-}
-
-
-
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index c24008cd6..99c960f7d 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -18,10 +18,10 @@
#include <linux/string.h>
#include <asm/uaccess.h>
-#include <linux/coda_namecache.h>
#include <linux/coda.h>
#include <linux/coda_linux.h>
-#include <linux/coda_cnode.h>
+#include <linux/coda_fs_i.h>
+#include <linux/coda_cache.h>
#include <linux/coda_psdev.h>
/* pioctl ops */
@@ -103,7 +103,7 @@ static int coda_pioctl(struct inode * inode, struct file * filp,
int error;
struct PioctlData data;
struct inode *target_inode = NULL;
- struct cnode *cnp;
+ struct coda_inode_info *cnp;
ENTRY;
/* get the Pioctl data arguments from user space */
@@ -115,16 +115,17 @@ static int coda_pioctl(struct inode * inode, struct file * filp,
* Look up the pathname. Note that the pathname is in
* user memory, and namei takes care of this
*/
- CDEBUG(D_PIOCTL, "namei, data.follow = %d\n", data.follow);
+ CDEBUG(D_PIOCTL, "namei, data.follow = %d\n",
+ data.follow);
if ( data.follow ) {
target_de = namei(data.path);
} else {
target_de = lnamei(data.path);
}
-
- if (!target_de) {
+
+ if ( PTR_ERR(target_de) == -ENOENT ) {
CDEBUG(D_PIOCTL, "error: lookup fails.\n");
- return -EINVAL;
+ return PTR_ERR(target_de);
} else {
target_inode = target_de->d_inode;
}
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index cd591d3e9..04333e046 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -17,6 +17,7 @@
* Copyright (c) 1997 Carnegie-Mellon University
*/
+#include <linux/config.h> /* for CONFIG_PROC_FS */
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -35,35 +36,75 @@
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/system.h>
+#include <asm/poll.h>
#include <asm/uaccess.h>
#include <linux/coda.h>
#include <linux/coda_linux.h>
+#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
-#include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_cache.h>
#include <linux/coda_sysctl.h>
+/*
+ * Where is the prototype?
+ */
+
+int proc_register_dynamic(struct proc_dir_entry * dir,
+ struct proc_dir_entry * dp);
+
/*
* Coda stuff
*/
extern struct file_system_type coda_fs_type;
-extern int coda_downcall(int opcode, struct outputArgs *out);
extern int init_coda_fs(void);
extern int cfsnc_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
extern int cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy);
/* statistics */
struct coda_upcallstats coda_callstats;
-
+int coda_hard = 0; /* introduces a timeout on upcalls */
+unsigned long coda_timeout = 10; /* .. secs, then signals will dequeue */
extern struct coda_sb_info coda_super_info[MAX_CODADEVS];
struct vcomm psdev_vcomm[MAX_CODADEVS];
-/*
- * Device operations
- */
+/* queue stuff for the messages */
+static inline void init_queue(struct queue *head)
+{
+ head->forw = head;
+ head->back = head;
+}
+
+static inline struct vmsg *q_getnext(struct queue *elt)
+{
+ return (struct vmsg *)(elt->forw);
+}
+
+static inline int q_end(struct vmsg *msg, struct queue *queue)
+{
+ return (struct queue *)msg == queue;
+}
+
+static inline int q_empty(struct queue *queue)
+{
+ return queue->forw == queue;
+}
+
+/* insert before head, ie. at the tail */
+void coda_q_insert(struct queue *el, struct queue *head)
+{
+ el->forw = head->back->forw;
+ el->back = head->back;
+ head->back->forw = el;
+ head->back = el;
+}
+void coda_q_remove(struct queue *el)
+{
+ el->forw->back = el->back;
+ el->back->forw = el->forw;
+}
static struct vcomm *coda_psdev2vcomm(struct file *file)
{
@@ -75,6 +116,10 @@ static struct vcomm *coda_psdev2vcomm(struct file *file)
return vcp;
}
+/*
+ * Device operations
+ */
+
static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
{
@@ -84,8 +129,8 @@ static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
if ( !vcp )
return -ENXIO;
- poll_wait(&(vcp->vc_waitq), wait);
- if (!EMPTY(vcp->vc_pending))
+ poll_wait(file, &(vcp->vc_waitq), wait);
+ if (!q_empty(&(vcp->vc_pending)))
mask |= POLLIN | POLLRDNORM;
return mask;
@@ -101,7 +146,6 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
{
struct vcomm *vcp = coda_psdev2vcomm(file);
struct vmsg *vmp;
- struct outputArgs *out;
int error = 0;
int size;
u_long uniq;
@@ -111,7 +155,7 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
if (!vcp)
return -ENXIO;
- /* Peek at the opcode, unique id */
+ /* Peek at the opcode, uniquefier */
if (copy_from_user(opcodebuf, buf, 2 * sizeof(u_long)))
return -EFAULT;
opcode = opcodebuf[0];
@@ -121,67 +165,69 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
current->pid, opcode, uniq);
if (DOWNCALL(opcode)) {
- struct outputArgs pbuf;
-
+ struct super_block *sb = NULL;
+ union outputArgs *dcbuf;
+ size = sizeof(*dcbuf);
+
+ sb = vcp->vc_sb;
+ if ( !sb ) {
+ printk("coda_psdev_write: downcall, no SB!\n");
+ return count;
+ }
CDEBUG(D_PSDEV, "handling downcall\n");
- /* get the rest of the data. */
- size = sizeof(pbuf);
- if ( count < sizeof(pbuf) ) {
- printk("Coda: downcall opc %ld, uniq %ld, not enough!\n",
+ if ( count < sizeof(struct cfs_out_hdr) ) {
+ printk("coda_downcall opc %ld uniq %ld, not enough!\n",
opcode, uniq);
- size =count;
- } else if ( count > sizeof(pbuf) ) {
+ return count;
+ }
+ CODA_ALLOC(dcbuf, union outputArgs *, size);
+ if ( count > size ) {
printk("Coda: downcall opc %ld, uniq %ld, too much!",
opcode, uniq);
- size = sizeof(pbuf);
+ count = size;
}
- if (copy_from_user(&pbuf, buf, size))
+ if (copy_from_user(dcbuf, buf, count))
return -EFAULT;
- /* what errors for coda_downcall should be
- * sent to Venus ?
- */
- error = coda_downcall(opcode, &pbuf);
+ /* what downcall errors does Venus handle ? */
+ error = coda_downcall(opcode, dcbuf, sb);
+
if ( error) {
printk("psdev_write: coda_downcall error: %d\n",
error);
return 0;
}
+ CODA_FREE(dcbuf, size);
return count;
}
/* Look for the message on the processing queue. */
- for (vmp = (struct vmsg *)GETNEXT(vcp->vc_processing);
- !EOQ(vmp, vcp->vc_processing);
- vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) {
- if (vmp->vm_unique == uniq) break;
- CDEBUG(D_PSDEV,"Eureka: uniq %ld on queue!\n", uniq);
+ for (vmp = q_getnext(&(vcp->vc_processing));
+ !q_end(vmp, &(vcp->vc_processing));
+ vmp = q_getnext(&(vmp->vm_chain))) {
+ if (vmp->vm_unique == uniq) {
+ break;
+ CDEBUG(D_PSDEV,"Eureka: uniq %ld on queue!\n", uniq);
+ }
}
- if (EOQ(vmp, vcp->vc_processing)) {
+ if (q_end(vmp, &(vcp->vc_processing))) {
printk("psdev_write: msg (%ld, %ld) not found\n",
opcode, uniq);
return(-ESRCH);
}
/* Remove the message from the processing queue */
- REMQUE(vmp->vm_chain);
+ coda_q_remove(&(vmp->vm_chain));
/* move data into response buffer. */
- /* Don't need to copy opcode and uniquifier. */
- out = (struct outputArgs *)vmp->vm_data;
- /* get the rest of the data. */
if (vmp->vm_outSize < count) {
- printk("Coda write: too much outs: %d, cnt: %d, opc: %ld, uniq: %ld.\n",
- vmp->vm_outSize, count, opcode, uniq);
- wake_up_interruptible(&vmp->vm_sleep);
- return -EINVAL;
- } else if (vmp->vm_outSize > count) {
- printk("Coda write: too much outs: %d, cnt: %d, opc: %ld, uniq: %ld.\n",
+ printk("psdev_write: too much cnt: %d, cnt: %d, opc: %ld, uniq: %ld.\n",
vmp->vm_outSize, count, opcode, uniq);
+ count = vmp->vm_outSize; /* don't have more space! */
}
- if (copy_from_user(out, buf, count))
+ if (copy_from_user(vmp->vm_data, buf, count))
return -EFAULT;
/* adjust outsize. is this usefull ?? */
@@ -192,7 +238,7 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
"Found! Count %d for (opc,uniq)=(%ld,%ld), vmsg at %x\n",
count, opcode, uniq, (int)&vmp);
- wake_up_interruptible(&vmp->vm_sleep);
+ wake_up(&vmp->vm_sleep);
return(count);
}
@@ -201,7 +247,7 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf,
*/
static ssize_t coda_psdev_read(struct file * file, char * buf,
- size_t count, loff_t *off)
+ size_t count, loff_t *off)
{
struct vcomm *vcp = coda_psdev2vcomm(file);
struct vmsg *vmp;
@@ -211,41 +257,39 @@ static ssize_t coda_psdev_read(struct file * file, char * buf,
return -ENXIO;
/* Get message at head of request queue. */
- if (EMPTY(vcp->vc_pending)) {
- return 0; /* Nothing to read */
+ if (q_empty(&(vcp->vc_pending))) {
+ return 0;
}
- vmp = (struct vmsg *)GETNEXT(vcp->vc_pending);
- REMQUE(vmp->vm_chain);
+ vmp = q_getnext(&(vcp->vc_pending));
+ coda_q_remove(&(vmp->vm_chain));
/* Move the input args into userspace */
-
if (vmp->vm_inSize <= count)
result = vmp->vm_inSize;
if (count < vmp->vm_inSize) {
- printk ("psdev_read: warning: venus read %d bytes of %d long
- message\n",count, vmp->vm_inSize);
+ printk ("psdev_read: Venus read %d bytes of %d in message\n",
+ count, vmp->vm_inSize);
}
if ( copy_to_user(buf, vmp->vm_data, result))
return -EFAULT;
if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
- coda_panic("coda_psdev_read: bad chain");
+ printk("coda_psdev_read: bad chain");
- /* If request was a signal, free up the message and don't
- enqueue it in the reply queue. */
+ /* If request was a signal, don't enqueue */
if (vmp->vm_opcode == CFS_SIGNAL) {
CDEBUG(D_PSDEV, "vcread: signal msg (%d, %d)\n",
vmp->vm_opcode, vmp->vm_unique);
- CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
- CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
+ CODA_FREE(vmp->vm_data, sizeof(struct cfs_in_hdr));
+ CODA_FREE(vmp, sizeof(struct vmsg));
return count;
}
vmp->vm_flags |= VM_READ;
- INSQUE(vmp->vm_chain, vcp->vc_processing);
+ coda_q_insert(&(vmp->vm_chain), &(vcp->vc_processing));
return result;
}
@@ -254,22 +298,22 @@ static ssize_t coda_psdev_read(struct file * file, char * buf,
static int coda_psdev_open(struct inode * inode, struct file * file)
{
register struct vcomm *vcp = NULL;
-
ENTRY;
- vcp = coda_psdev2vcomm(file);
+ vcp =coda_psdev2vcomm(file);
if (!vcp)
- return -ENODEV;
- memset(vcp, 0, sizeof(struct vcomm));
+ return -ENODEV;
- MOD_INC_USE_COUNT;
+ if (vcp->vc_inuse)
+ return -EBUSY;
- INIT_QUEUE(vcp->vc_pending);
- INIT_QUEUE(vcp->vc_processing);
+ memset(vcp, 0, sizeof(struct vcomm));
+ vcp->vc_inuse = 1;
+ MOD_INC_USE_COUNT;
- cfsnc_init();
- CDEBUG(D_PSDEV, "Name cache initialized.\n");
+ init_queue(&(vcp->vc_pending));
+ init_queue(&(vcp->vc_processing));
memset(&coda_callstats, 0, sizeof(struct coda_upcallstats));
EXIT;
@@ -283,6 +327,7 @@ coda_psdev_release(struct inode * inode, struct file * file)
struct vcomm *vcp;
struct vmsg *vmp;
unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ ENTRY;
vcp = coda_psdev2vcomm(file);
@@ -294,49 +339,44 @@ coda_psdev_release(struct inode * inode, struct file * file)
/* flush the name cache so that we can unmount */
CDEBUG(D_PSDEV, "Flushing the cache.\n");
- cfsnc_flush();
- cfsnc_use = 0;
+ /* cfsnc_flush(); */
+ /* cfsnc_use = 0; */
CDEBUG(D_PSDEV, "Done.\n");
- /* prevent future operations on this vfs from succeeding by
- * auto- unmounting any vfs mounted via this device. This
- * frees user or sysadm from having to remember where all
- * mount points are located. Put this before WAKEUPs to avoid
- * queuing new messages between the WAKEUP and the unmount
- * (which can happen if we're unlucky) */
-
+ /* if operations are in progress perhaps the kernel
+ can profit from setting the C_DYING flag on the root
+ cnode of Coda filesystems */
if (coda_super_info[minor].sbi_root) {
- struct cnode *cnp = ITOC(coda_super_info[minor].sbi_root);
- /* Let unmount know this is for real */
+ struct coda_inode_info *cnp =
+ ITOC(coda_super_info[minor].sbi_root);
cnp->c_flags |= C_DYING;
- /* XXX Could we force an unmount here? */
- }
+ } else
+ vcp->vc_inuse = 0;
/* Wakeup clients so they can return. */
- for (vmp = (struct vmsg *)GETNEXT(vcp->vc_pending);
- !EOQ(vmp, vcp->vc_pending);
- vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) {
+ for (vmp = q_getnext(&(vcp->vc_pending));
+ !q_end(vmp, &(vcp->vc_pending));
+ vmp = q_getnext(&(vmp->vm_chain))) {
/* Free signal request messages and don't wakeup cause
no one is waiting. */
if (vmp->vm_opcode == CFS_SIGNAL) {
- CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
- CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
+ CODA_FREE(vmp->vm_data, sizeof(struct cfs_in_hdr));
+ CODA_FREE(vmp, (u_int)sizeof(struct vmsg));
continue;
}
-
- wake_up_interruptible(&vmp->vm_sleep);
+ wake_up(&vmp->vm_sleep);
}
- for (vmp = (struct vmsg *)GETNEXT(vcp->vc_processing);
- !EOQ(vmp, vcp->vc_processing);
- vmp = (struct vmsg *)GETNEXT(vmp->vm_chain)) {
- wake_up_interruptible(&vmp->vm_sleep);
+ for (vmp = q_getnext(&(vcp->vc_processing));
+ !q_end(vmp, &(vcp->vc_processing));
+ vmp = q_getnext(&(vmp->vm_chain))) {
+ wake_up(&vmp->vm_sleep);
}
mark_vcomm_closed(vcp);
- cfsnc_use = 0;
- MOD_DEC_USE_COUNT;
+ MOD_DEC_USE_COUNT;
+ EXIT;
return 0;
}
@@ -358,35 +398,16 @@ static struct file_operations coda_psdev_fops = {
NULL /* lock */
};
-int init_coda_psdev(void)
-{
-
- if(register_chrdev(CODA_PSDEV_MAJOR,"coda_psdev", &coda_psdev_fops)) {
- printk(KERN_ERR "coda_psdev: unable to get major %d\n",
- CODA_PSDEV_MAJOR);
- return -EIO;
- }
-
- return 0;
-}
-
#ifdef CONFIG_PROC_FS
struct proc_dir_entry proc_coda = {
0, 4, "coda",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
+ S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR, 2, 0, 0,
0, &proc_net_inode_operations,
};
-struct proc_dir_entry proc_coda_cache = {
- 0 , 10, "coda-cache",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- cfsnc_get_info
- };
-
struct proc_dir_entry proc_coda_ncstats = {
0 , 12, "coda-ncstats",
S_IFREG | S_IRUGO, 1, 0, 0,
@@ -396,25 +417,48 @@ struct proc_dir_entry proc_coda_ncstats = {
#endif
-#ifdef MODULE
-int init_module(void)
+
+int init_coda_psdev(void)
{
- int status;
- printk(KERN_INFO "Coda Kernel/User communications module 0.04\n");
+ if(register_chrdev(CODA_PSDEV_MAJOR,"coda_psdev", &coda_psdev_fops)) {
+ printk(KERN_ERR "coda_psdev: unable to get major %d\n",
+ CODA_PSDEV_MAJOR);
+ return -EIO;
+ }
+ memset(psdev_vcomm, 0, sizeof(psdev_vcomm));
+ memset(coda_super_info, 0, sizeof(coda_super_info));
+ memset(&coda_callstats, 0, sizeof(coda_callstats));
#ifdef CONFIG_PROC_FS
- proc_register(&proc_root,&proc_coda);
- proc_register(&proc_coda, &proc_coda_cache);
- proc_register(&proc_coda, &proc_coda_ncstats);
- coda_sysctl_init();
+ proc_register(&proc_root,&proc_coda);
+ proc_register(&proc_coda, &proc_coda_ncstats);
+ coda_sysctl_init();
#endif
+ return 0;
+}
+
+
+#ifdef MODULE
+
+EXPORT_NO_SYMBOLS;
- init_coda_psdev();
-
- if ((status = init_coda_fs()) != 0)
- {
- printk("coda: failed in init_coda_fs!\n");
- }
+MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
+
+int init_module(void)
+{
+ int status;
+ printk(KERN_INFO "Coda Kernel/User communications module 1.0\n");
+
+ status = init_coda_psdev();
+ if ( status ) {
+ printk("Problem (%d) in init_coda_psdev\n", status);
+ return status;
+ }
+
+ status = init_coda_fs();
+ if (status) {
+ printk("coda: failed in init_coda_fs!\n");
+ }
return status;
}
@@ -425,14 +469,13 @@ void cleanup_module(void)
ENTRY;
- unregister_chrdev(CODA_PSDEV_MAJOR,"coda_psdev");
-
if ( (err = unregister_filesystem(&coda_fs_type)) != 0 ) {
printk("coda: failed to unregister filesystem\n");
}
+ unregister_chrdev(CODA_PSDEV_MAJOR,"coda_psdev");
+
#if CONFIG_PROC_FS
coda_sysctl_clean();
- proc_unregister(&proc_coda, proc_coda_cache.low_ino);
proc_unregister(&proc_coda, proc_coda_ncstats.low_ino);
proc_unregister(&proc_root, proc_coda.low_ino);
#endif
@@ -440,5 +483,3 @@ void cleanup_module(void)
#endif
-
-
diff --git a/fs/coda/super.c b/fs/coda/super.c
index 85a5ccbb3..5410fb50d 100644
--- a/fs/coda/super.c
+++ b/fs/coda/super.c
@@ -1,13 +1,14 @@
/*
* Super block/filesystem wide operations
*
- * Peter J. Braam <braam@maths.ox.ac.uk>,
- * Michael Callahan <callahan@maths.ox.ac.uk> Aug 1996
- * Rewritten for Linux 2.1.57 Peter Braam <braam@cs.cmu.edu>
+ * Copryright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and
+ * Michael Callahan <callahan@maths.ox.ac.uk>
+ *
+ * Rewritten for Linux 2.1.?? Peter Braam <braam@cs.cmu.edu>
+ * Copyright (C) Carnegie Mellon University
*/
#define __NO_VERSION__
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -32,45 +33,25 @@
#include <linux/coda.h>
#include <linux/coda_linux.h>
#include <linux/coda_psdev.h>
-#include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_fs_i.h>
+#include <linux/coda_cache.h>
/* VFS super_block ops */
static struct super_block *coda_read_super(struct super_block *, void *, int);
static void coda_read_inode(struct inode *);
-static int coda_notify_change(struct inode *inode, struct iattr *attr);
+static int coda_notify_change(struct dentry *dentry, struct iattr *attr);
static void coda_put_inode(struct inode *);
static void coda_delete_inode(struct inode *);
static void coda_put_super(struct super_block *);
static int coda_statfs(struct super_block *sb, struct statfs *buf,
int bufsiz);
-
/* helper functions */
-void print_vattr( struct coda_vattr *attr );
-static inline struct coda_sb_info *coda_psinode2sb(struct inode *inode);
static inline struct vcomm *coda_psinode2vcomm(struct inode *inode);
static int coda_get_psdev(void *, struct inode **);
-static void coda_vattr_to_iattr(struct inode *, struct coda_vattr *);
-static void coda_iattr_to_vattr(struct iattr *, struct coda_vattr *);
-int coda_fetch_inode(struct inode *, struct coda_vattr *);
-
-extern inline struct vcomm *coda_psdev_vcomm(struct inode *inode);
-extern int coda_cnode_make(struct inode **inode, ViceFid *fid,
- struct super_block *sb);
-extern struct cnode *coda_cnode_alloc(void);
-extern void coda_cnode_free(struct cnode *);
-char *coda_f2s(struct ViceFid *, char *);
-
-extern int cfsnc_initialized;
-extern int coda_debug;
-extern int coda_print_entry;
-
-extern struct inode_operations coda_file_inode_operations;
-extern struct inode_operations coda_dir_inode_operations;
-extern struct inode_operations coda_ioctl_inode_operations;
-extern struct inode_operations coda_symlink_inode_operations;
+static struct coda_sb_info *coda_psinode2sbi(struct inode *inode);
+
/* exported operations */
struct super_operations coda_super_operations =
{
@@ -91,37 +72,39 @@ struct super_operations coda_super_operations =
struct coda_sb_info coda_super_info[MAX_CODADEVS];
-
static struct super_block * coda_read_super(struct super_block *sb,
void *data, int silent)
{
struct inode *psdev = 0, *root = 0;
struct coda_sb_info *sbi = NULL;
- struct vcomm *vc;
+ struct vcomm *vc = NULL;
ViceFid fid;
kdev_t dev = sb->s_dev;
int error;
char str[50];
-ENTRY;
+ ENTRY;
MOD_INC_USE_COUNT;
if (coda_get_psdev(data, &psdev))
- goto exit;
+ goto error;
vc = coda_psinode2vcomm(psdev);
if ( !vc )
- goto exit;
+ goto error;
+ vc->vc_sb = sb;
+ vc->vc_inuse = 1;
- sbi = coda_psinode2sb(psdev);
+ sbi = coda_psinode2sbi(psdev);
if ( !sbi )
- goto exit;
-
+ goto error;
sbi->sbi_psdev = psdev;
sbi->sbi_vcomm = vc;
+ INIT_LIST_HEAD(&(sbi->sbi_cchead));
+ INIT_LIST_HEAD(&(sbi->sbi_volroothead));
lock_super(sb);
sb->u.generic_sbp = sbi;
- sb->s_blocksize = 1024; /* XXXXX */
+ sb->s_blocksize = 1024; /* XXXXX what do we put here?? */
sb->s_blocksize_bits = 10;
sb->s_magic = CODA_SUPER_MAGIC;
sb->s_dev = dev;
@@ -129,22 +112,22 @@ ENTRY;
/* get root fid from Venus: this needs the root inode */
error = venus_rootfid(sb, &fid);
-
if ( error ) {
- unlock_super(sb);
printk("coda_read_super: coda_get_rootfid failed with %d\n",
- error);
- goto exit;
+ error);
+ sb->s_dev = 0;
+ unlock_super(sb);
+ goto error;
}
- printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid, str));
+ printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid));
+ /* make root inode */
error = coda_cnode_make(&root, &fid, sb);
if ( error || !root ) {
printk("Failure of coda_cnode_make for root: error %d\n", error);
- unlock_super(sb);
sb->s_dev = 0;
- root = NULL;
- goto exit;
+ unlock_super(sb);
+ goto error;
}
printk("coda_read_super: rootinode is %ld dev %d\n",
@@ -152,22 +135,27 @@ ENTRY;
sbi->sbi_root = root;
sb->s_root = d_alloc_root(root, NULL);
unlock_super(sb);
+ EXIT;
return sb;
-EXIT;
-exit:
+error:
+EXIT;
MOD_DEC_USE_COUNT;
- sbi->sbi_vcomm = NULL;
- sbi->sbi_root = NULL;
+ if (sbi) {
+ sbi->sbi_vcomm = NULL;
+ sbi->sbi_root = NULL;
+ }
+ if ( vc ) {
+ vc->vc_sb = NULL;
+ vc->vc_inuse = 0;
+ }
if (root) {
iput(root);
- coda_cnode_free(ITOC(root));
}
sb->s_dev = 0;
return NULL;
}
-
static void coda_put_super(struct super_block *sb)
{
struct coda_sb_info *sb_info;
@@ -177,78 +165,94 @@ static void coda_put_super(struct super_block *sb)
lock_super(sb);
sb->s_dev = 0;
+ coda_cache_clear_all(sb);
sb_info = coda_sbp(sb);
+ sb_info->sbi_vcomm->vc_inuse = 0;
+ sb_info->sbi_vcomm->vc_sb = NULL;
+ printk("Coda: Bye bye.\n");
memset(sb_info, 0, sizeof(* sb_info));
unlock_super(sb);
MOD_DEC_USE_COUNT;
-EXIT;
+ EXIT;
}
+
/* all filling in of inodes postponed until lookup */
static void coda_read_inode(struct inode *inode)
{
- inode->u.generic_ip = NULL;
- /* inode->i_blksize = inode->i_sb->s_blocksize;
- inode->i_mode = 0;
- inode->i_op = NULL;
- NFS_CACHEINV(inode); */
+ struct coda_inode_info *cnp;
+ ENTRY;
+ cnp = ITOC(inode);
+ cnp->c_magic = 0;
+ return;
}
-static void coda_put_inode(struct inode *inode)
+static void coda_put_inode(struct inode *in)
{
- CDEBUG(D_INODE,"ino: %ld, cnp: %x\n", inode->i_ino,
- (int) inode->u.generic_ip);
+ ENTRY;
+
+ CDEBUG(D_INODE,"ino: %ld, count %d\n", in->i_ino, in->i_count);
+
+ if ( in->i_count == 1 )
+ in->i_nlink = 0;
+
}
static void coda_delete_inode(struct inode *inode)
{
- struct cnode *cnp;
+ struct coda_inode_info *cnp;
struct inode *open_inode;
ENTRY;
CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n",
inode->i_ino, inode->i_count);
- if ( inode->i_ino == CTL_INO ) {
+ cnp = ITOC(inode);
+ if ( inode->i_ino == CTL_INO || cnp->c_magic != CODA_CNODE_MAGIC ) {
clear_inode(inode);
return;
}
- cnp = ITOC(inode);
+
+ if ( coda_fid_is_volroot(&cnp->c_fid) )
+ list_del(&cnp->c_volrootlist);
open_inode = cnp->c_ovp;
if ( open_inode ) {
CDEBUG(D_SUPER, "DELINO cached file: ino %ld count %d.\n",
open_inode->i_ino, open_inode->i_count);
cnp->c_ovp = NULL;
- cnp->c_odentry.d_inode = NULL;
- iput( open_inode );
+ iput(open_inode);
}
+
+ coda_cache_clear_cnp(cnp);
+
inode->u.generic_ip = NULL;
- coda_cnode_free(cnp);
clear_inode(inode);
-EXIT;
+ EXIT;
}
-static int coda_notify_change(struct inode *inode, struct iattr *iattr)
+static int coda_notify_change(struct dentry *de, struct iattr *iattr)
{
- struct cnode *cnp;
+ struct inode *inode = de->d_inode;
+ struct coda_inode_info *cnp;
struct coda_vattr vattr;
int error;
-ENTRY;
+
+ ENTRY;
memset(&vattr, 0, sizeof(vattr));
cnp = ITOC(inode);
CHECK_CNODE(cnp);
coda_iattr_to_vattr(iattr, &vattr);
- vattr.va_type = VNON; /* cannot set type */
+ vattr.va_type = C_VNON; /* cannot set type */
CDEBUG(D_SUPER, "vattr.va_mode %o\n", vattr.va_mode);
error = venus_setattr(inode->i_sb, &cnp->c_fid, &vattr);
if ( !error ) {
coda_vattr_to_iattr(inode, &vattr);
- cfsnc_zapfid(&(cnp->c_fid));
+ coda_cache_clear_cnp(cnp);
}
CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n",
inode->i_mode, error);
@@ -257,14 +261,12 @@ ENTRY;
return error;
}
-/* we need _something_ */
+/* we need _something_ for this routine. Let's mimic AFS */
static int coda_statfs(struct super_block *sb, struct statfs *buf,
int bufsiz)
{
struct statfs tmp;
-#define NB_SFS_SIZ 0x895440
-
tmp.f_type = CODA_SUPER_MAGIC;
tmp.f_bsize = 1024;
tmp.f_blocks = 9000000;
@@ -284,278 +286,38 @@ struct file_system_type coda_fs_type = {
"coda", 0, coda_read_super, NULL
};
-
-
-
int init_coda_fs(void)
{
return register_filesystem(&coda_fs_type);
}
+/* MODULE stuff is in psdev.c */
-/* utility functions below */
-static void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
-{
- int inode_type;
- /* inode's i_dev, i_flags, i_ino are set by iget
- XXX: is this all we need ??
- */
- switch (attr->va_type) {
- case VNON:
- inode_type = 0;
- break;
- case VREG:
- inode_type = S_IFREG;
- break;
- case VDIR:
- inode_type = S_IFDIR;
- break;
- case VLNK:
- inode_type = S_IFLNK;
- break;
- default:
- inode_type = 0;
- }
- inode->i_mode |= inode_type;
-
- if (attr->va_mode != (u_short) -1)
- inode->i_mode = attr->va_mode | inode_type;
- if (attr->va_uid != -1)
- inode->i_uid = (uid_t) attr->va_uid;
- if (attr->va_gid != -1)
- inode->i_gid = (gid_t) attr->va_gid;
- if (attr->va_nlink != -1)
- inode->i_nlink = attr->va_nlink;
- if (attr->va_size != -1)
- inode->i_size = attr->va_size;
- /* XXX This needs further study */
- /*
- inode->i_blksize = attr->va_blocksize;
- inode->i_blocks = attr->va_size/attr->va_blocksize
- + (attr->va_size % attr->va_blocksize ? 1 : 0);
- */
- if (attr->va_atime.tv_sec != -1)
- inode->i_atime = attr->va_atime.tv_sec;
- if (attr->va_mtime.tv_sec != -1)
- inode->i_mtime = attr->va_mtime.tv_sec;
- if (attr->va_ctime.tv_sec != -1)
- inode->i_ctime = attr->va_ctime.tv_sec;
-}
-/*
- * BSD sets attributes that need not be modified to -1.
- * Linux uses the valid field to indicate what should be
- * looked at. The BSD type field needs to be deduced from linux
- * mode.
- * So we have to do some translations here.
- */
-
-void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr)
-{
- umode_t mode;
- unsigned int valid;
-
- /* clean out */
- vattr->va_mode = (umode_t) -1;
- vattr->va_uid = (vuid_t) -1;
- vattr->va_gid = (vgid_t) -1;
- vattr->va_size = (off_t) -1;
- vattr->va_atime.tv_sec = (time_t) -1;
- vattr->va_mtime.tv_sec = (time_t) -1;
- vattr->va_ctime.tv_sec = (time_t) -1;
- vattr->va_atime.tv_nsec = (time_t) -1;
- vattr->va_mtime.tv_nsec = (time_t) -1;
- vattr->va_ctime.tv_nsec = (time_t) -1;
- vattr->va_type = VNON;
- vattr->va_fileid = (long)-1;
- vattr->va_gen = (long)-1;
- vattr->va_bytes = (long)-1;
- vattr->va_fsid = (long)-1;
- vattr->va_nlink = (short)-1;
- vattr->va_blocksize = (long)-1;
- vattr->va_rdev = (dev_t)-1;
- vattr->va_flags = 0;
-
- /* determine the type */
- mode = iattr->ia_mode;
- if ( S_ISDIR(mode) ) {
- vattr->va_type = VDIR;
- } else if ( S_ISREG(mode) ) {
- vattr->va_type = VREG;
- } else if ( S_ISLNK(mode) ) {
- vattr->va_type = VLNK;
- } else {
- /* don't do others */
- vattr->va_type = VNON;
- }
-
- /* set those vattrs that need change */
- valid = iattr->ia_valid;
- if ( valid & ATTR_MODE ) {
- vattr->va_mode = iattr->ia_mode;
- }
- if ( valid & ATTR_UID ) {
- vattr->va_uid = (vuid_t) iattr->ia_uid;
- }
- if ( valid & ATTR_GID ) {
- vattr->va_gid = (vgid_t) iattr->ia_gid;
- }
- if ( valid & ATTR_SIZE ) {
- vattr->va_size = iattr->ia_size;
- }
- if ( valid & ATTR_ATIME ) {
- vattr->va_atime.tv_sec = iattr->ia_atime;
- vattr->va_atime.tv_nsec = 0;
- }
- if ( valid & ATTR_MTIME ) {
- vattr->va_mtime.tv_sec = iattr->ia_mtime;
- vattr->va_mtime.tv_nsec = 0;
- }
- if ( valid & ATTR_CTIME ) {
- vattr->va_ctime.tv_sec = iattr->ia_ctime;
- vattr->va_ctime.tv_nsec = 0;
- }
-
-}
-
-
-void print_vattr(struct coda_vattr *attr)
-{
- char *typestr;
-
- switch (attr->va_type) {
- case VNON:
- typestr = "VNON";
- break;
- case VREG:
- typestr = "VREG";
- break;
- case VDIR:
- typestr = "VDIR";
- break;
- case VBLK:
- typestr = "VBLK";
- break;
- case VCHR:
- typestr = "VCHR";
- break;
- case VLNK:
- typestr = "VLNK";
- break;
- case VSOCK:
- typestr = "VSCK";
- break;
- case VFIFO:
- typestr = "VFFO";
- break;
- case VBAD:
- typestr = "VBAD";
- break;
- default:
- typestr = "????";
- break;
- }
-
-
- printk("attr: type %s (%o) mode %o uid %d gid %d fsid %d rdev %d\n",
- typestr, (int)attr->va_type, (int)attr->va_mode, (int)attr->va_uid,
- (int)attr->va_gid, (int)attr->va_fsid, (int)attr->va_rdev);
-
- printk(" fileid %d nlink %d size %d blocksize %d bytes %d\n",
- (int)attr->va_fileid, (int)attr->va_nlink,
- (int)attr->va_size,
- (int)attr->va_blocksize,(int)attr->va_bytes);
- printk(" gen %ld flags %ld vaflags %d\n",
- attr->va_gen, attr->va_flags, attr->va_vaflags);
- printk(" atime sec %d nsec %d\n",
- (int)attr->va_atime.tv_sec, (int)attr->va_atime.tv_nsec);
- printk(" mtime sec %d nsec %d\n",
- (int)attr->va_mtime.tv_sec, (int)attr->va_mtime.tv_nsec);
- printk(" ctime sec %d nsec %d\n",
- (int)attr->va_ctime.tv_sec, (int)attr->va_ctime.tv_nsec);
-}
-
-/* */
-int coda_fetch_inode (struct inode *inode, struct coda_vattr *attr)
-{
- struct cnode *cp;
- int ino, error=0;
- CDEBUG(D_SUPER, "fetch for ino: %ld\n", inode->i_ino);
-
- ino = inode->i_ino;
- if (!ino)
- printk("coda_fetch_inode: inode called with i_ino = 0 (don't worry)\n");
-
- inode->i_op = NULL;
- inode->i_mode = 0;
-
- cp = ITOC(inode);
- CHECK_CNODE(cp);
-
- /* root inode */
- if (cp->c_fid.Volume == 0 &&
- cp->c_fid.Vnode == 0 &&
- cp->c_fid.Unique == 0) {
- inode->i_ino = 1;
- inode->i_op = NULL;
- return 0;
- }
-
- if (IS_CTL_FID( &(cp->c_fid) )) {
- /* This is the special magic control file.
- Venus doesn't want
- to hear a GETATTR about this! */
- inode->i_op = &coda_ioctl_inode_operations;
- return 0;
- }
-
- if ( ! attr ) {
- printk("coda_fetch_inode: called with NULL vattr, ino %ld\n",
- inode->i_ino);
- return -1; /* XXX */
- }
-
- if (coda_debug & D_SUPER ) print_vattr(attr);
- coda_vattr_to_iattr(inode, attr);
-
- if (S_ISREG(inode->i_mode))
- inode->i_op = &coda_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
- inode->i_op = &coda_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &coda_symlink_inode_operations;
- else {
- printk ("coda_read_inode: what kind of inode is this? i_mode = %o\n", inode->i_mode);
- inode->i_op = NULL;
- }
- return error;
-}
-
-static inline struct vcomm *
-coda_psinode2vcomm(struct inode *inode)
+/* helpers */
+static inline struct vcomm *coda_psinode2vcomm(struct inode *inode)
{
unsigned int minor = MINOR(inode->i_rdev);
-CDEBUG(D_PSDEV,"minor %d\n", minor);
+ CDEBUG(D_PSDEV,"minor %d\n", minor);
if ( minor < MAX_CODADEVS )
return &(psdev_vcomm[minor]);
else
return NULL;
}
-static inline struct coda_sb_info *
-coda_psinode2sb(struct inode *inode)
+static struct coda_sb_info *coda_psinode2sbi(struct inode *inode)
{
unsigned int minor = MINOR(inode->i_rdev);
-CDEBUG(D_PSDEV,"minor %d\n", minor);
- if ( minor < MAX_CODADEVS )
+ CDEBUG(D_PSDEV,"minor %d\n", minor);
+ if ( (minor >= 0) && (minor < MAX_CODADEVS))
return &(coda_super_info[minor]);
else
return NULL;
}
-static int
-coda_get_psdev(void *data, struct inode **res_dev)
+/* name lookup for psdev passed in by mount */
+static int coda_get_psdev(void *data, struct inode **res_dev)
{
char **psdev_path;
struct inode *psdev = 0;
@@ -563,50 +325,46 @@ coda_get_psdev(void *data, struct inode **res_dev)
if ( ! data ) {
- printk("coda_read_super: no data!\n");
- goto error;
- } else {
- psdev_path = data;
- }
+ printk("coda_get_psdev: no data!\n");
+ return 1;
+ }
+
+ psdev_path = data;
ent = namei((char *) *psdev_path);
if (IS_ERR(ent)) {
printk("namei error %ld for %d\n", PTR_ERR(ent),
(int) psdev_path);
- goto error;
+ return 1;
}
psdev = ent->d_inode;
-
if (!S_ISCHR(psdev->i_mode)) {
printk("not a character device\n");
- goto error;
+ return 1;
}
-CDEBUG(D_PSDEV,"major %d, minor %d, count %d\n", MAJOR(psdev->i_rdev),
- MINOR(psdev->i_rdev), psdev->i_count);
+ CDEBUG(D_PSDEV,"major %d, minor %d, count %d\n",
+ MAJOR(psdev->i_rdev),
+ MINOR(psdev->i_rdev), psdev->i_count);
if (MAJOR(psdev->i_rdev) != CODA_PSDEV_MAJOR) {
printk("device %d not a Coda PSDEV device\n",
MAJOR(psdev->i_rdev));
- goto error;
+ return 1;
}
if (MINOR(psdev->i_rdev) >= MAX_CODADEVS) {
printk("minor %d not an allocated Coda PSDEV\n",
psdev->i_rdev);
- goto error;
+ return 1;
}
if (psdev->i_count < 1) {
printk("coda device minor %d not open (i_count = %d)\n",
MINOR(psdev->i_rdev), psdev->i_count);
- goto error;
+ return 1;
}
*res_dev = psdev;
-
+ EXIT;
return 0;
-
-EXIT;
-error:
- return 1;
}
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
index 432b806f8..c6d770a20 100644
--- a/fs/coda/symlink.c
+++ b/fs/coda/symlink.c
@@ -21,10 +21,11 @@
#include <linux/coda.h>
#include <linux/coda_linux.h>
#include <linux/coda_psdev.h>
-#include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_fs_i.h>
+#include <linux/coda_cache.h>
-static int coda_readlink(struct inode *inode, char *buffer, int length);
+static int coda_readlink(struct dentry *de, char *buffer, int length);
+static struct dentry *coda_follow_link(struct dentry *, struct dentry *);
struct inode_operations coda_symlink_inode_operations = {
NULL, /* no file-operations */
@@ -38,7 +39,7 @@ struct inode_operations coda_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
coda_readlink, /* readlink */
- NULL, /* follow_link */
+ coda_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -49,12 +50,13 @@ struct inode_operations coda_symlink_inode_operations = {
NULL /* revalidate */
};
-static int coda_readlink(struct inode *inode, char *buffer, int length)
+static int coda_readlink(struct dentry *de, char *buffer, int length)
{
+ struct inode *inode = de->d_inode;
int len;
int error;
char *buf;
- struct cnode *cp;
+ struct coda_inode_info *cp;
ENTRY;
cp = ITOC(inode);
@@ -76,7 +78,44 @@ static int coda_readlink(struct inode *inode, char *buffer, int length)
copy_to_user(buffer, buf, len);
put_user('\0', buffer + len);
error = len;
- CODA_FREE(buf, len);
}
+ if ( buf )
+ CODA_FREE(buf, len);
return error;
}
+
+static struct dentry *coda_follow_link(struct dentry *de,
+ struct dentry *base)
+{
+ struct inode *inode = de->d_inode;
+ int error;
+ struct coda_inode_info *cnp;
+ unsigned int len;
+ char mem[CFS_MAXPATHLEN];
+ char *path;
+ENTRY;
+ CDEBUG(D_INODE, "(%x/%ld)\n", inode->i_dev, inode->i_ino);
+
+ cnp = ITOC(inode);
+ CHECK_CNODE(cnp);
+
+ len = CFS_MAXPATHLEN;
+ error = venus_readlink(inode->i_sb, &(cnp->c_fid), mem, &len);
+
+ if (error) {
+ dput(base);
+ return ERR_PTR(error);
+ }
+ len = strlen(mem);
+ path = kmalloc(len + 1, GFP_KERNEL);
+ if (!path) {
+ dput(base);
+ return ERR_PTR(-ENOMEM);
+ }
+ memcpy(path, mem, len);
+ path[len] = 0;
+
+ base = lookup_dentry(path, base, 1);
+ kfree(path);
+ return base;
+}
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c
index 04523a383..c21016030 100644
--- a/fs/coda/sysctl.c
+++ b/fs/coda/sysctl.c
@@ -21,14 +21,18 @@
#include <asm/uaccess.h>
#include <linux/utsname.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda.h>
+#include <linux/coda_linux.h>
+#include <linux/coda_fs_i.h>
+#include <linux/coda_psdev.h>
+#include <linux/coda_cache.h>
#include <linux/coda_sysctl.h>
extern int coda_debug;
-extern int cfsnc_use;
+/* extern int cfsnc_use; */
extern int coda_print_entry;
-extern int cfsnc_flushme;
+/* extern int cfsnc_flushme; */
extern int cfsnc_procsize;
-extern void cfsnc_flush(void);
+/* extern void cfsnc_flush(void); */
void coda_sysctl_init(void);
void coda_sysctl_clean(void);
@@ -38,20 +42,20 @@ int coda_dointvec(ctl_table *table, int write, struct file *filp,
struct ctl_table_header *fs_table_header, *coda_table_header;
#define FS_CODA 1 /* Coda file system */
-#define CODA_DEBUG 1 /* control debugging */
-#define CODA_ENTRY 2 /* control enter/leave pattern */
-#define CODA_FLUSH 3 /* flush the cache on next lookup */
-#define CODA_MC 4 /* use/do not use the minicache */
-#define CODA_PROCSIZE 5 /* resize the cache on next lookup */
+#define CODA_DEBUG 1 /* control debugging */
+#define CODA_ENTRY 2 /* control enter/leave pattern */
+#define CODA_TIMEOUT 3 /* timeout on upcalls to become intrble */
+#define CODA_MC 4 /* use/do not use the access cache */
+#define CODA_HARD 5 /* mount type "hard" or "soft" */
static ctl_table coda_table[] = {
{CODA_DEBUG, "debug", &coda_debug, sizeof(int), 0644, NULL, &coda_dointvec},
{CODA_ENTRY, "printentry", &coda_print_entry, sizeof(int), 0644, NULL, &coda_dointvec},
- {CODA_MC, "minicache", &cfsnc_use, sizeof(int), 0644, NULL, &coda_dointvec},
- {CODA_FLUSH, "flushme", &cfsnc_flushme, sizeof(int), 0644, NULL, &coda_dointvec},
- {CODA_PROCSIZE, "resize", &cfsnc_procsize, sizeof(int), 0644, NULL, &coda_dointvec},
+ {CODA_MC, "accesscache", &coda_access_cache, sizeof(int), 0644, NULL, &coda_dointvec},
+ {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &coda_dointvec},
+ {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &coda_dointvec},
{ 0 }
};
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 43536f622..ac625ad17 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -16,7 +16,8 @@
#include <asm/system.h>
#include <asm/segment.h>
-
+#include <asm/signal.h>
+#include <linux/signal.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -34,34 +35,54 @@
#include <linux/coda.h>
#include <linux/coda_linux.h>
#include <linux/coda_psdev.h>
-#include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
+#include <linux/coda_fs_i.h>
+#include <linux/coda_cache.h>
+
+#define UPARG(op)\
+do {\
+ CODA_ALLOC(inp, union inputArgs *, insize);\
+ outp = (union outputArgs *) (inp);\
+ inp->ih.opcode = (op);\
+ inp->ih.pid = current->pid;\
+ inp->ih.pgid = current->pgrp;\
+ coda_load_creds(&(inp->ih.cred));\
+ outsize = insize;\
+} while (0)
+
+static inline int max(int a, int b)
+{
+ if ( a > b )
+ return a;
+ else
+ return b;
+}
+#define INSIZE(tag) sizeof(struct cfs_ ## tag ## _in)
+#define OUTSIZE(tag) sizeof(struct cfs_ ## tag ## _out)
+#define SIZE(tag) max(INSIZE(tag), OUTSIZE(tag))
-static vcsize = (sizeof(struct inputArgs) > sizeof(struct outputArgs)) ?
- sizeof(struct inputArgs): sizeof(struct outputArgs);
/* the upcalls */
int venus_rootfid(struct super_block *sb, ViceFid *fidp)
{
- struct inputArgs *inp;
- struct outputArgs *outp;
- int error=0;
- int size;
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
ENTRY;
- UPARG(vcsize, CFS_ROOT);
- error = coda_upcall(coda_sbp(sb), VC_IN_NO_DATA, &size, inp);
+ insize = SIZE(root);
+ UPARG(CFS_ROOT);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if (error) {
printk("coda_get_rootfid: error %d\n", error);
} else {
- *fidp = (ViceFid) outp->d.cfs_root.VFid;
+ *fidp = (ViceFid) outp->cfs_root.VFid;
CDEBUG(D_SUPER, "VolumeId: %lx, VnodeId: %lx.\n",
fidp->Volume, fidp->Vnode);
}
- if (inp) CODA_FREE(inp, VC_IN_NO_DATA);
+ if (inp) CODA_FREE(inp, insize);
EXIT;
return -error;
}
@@ -69,19 +90,19 @@ ENTRY;
int venus_getattr(struct super_block *sb, struct ViceFid *fid,
struct coda_vattr *attr)
{
- struct inputArgs *inp;
- struct outputArgs *outp;
- int size, error;
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
ENTRY;
-
- UPARG(vcsize, CFS_GETATTR);
- inp->d.cfs_getattr.VFid = *fid;
- error = coda_upcall(coda_sbp(sb), vcsize, &size, inp);
+ insize = SIZE(getattr);
+ UPARG(CFS_GETATTR);
+ inp->cfs_getattr.VFid = *fid;
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if ( !error )
- *attr = (struct coda_vattr) outp->d.cfs_getattr.attr;
+ *attr = outp->cfs_getattr.attr;
- if (inp) CODA_FREE(inp, sizeof(struct inputArgs));
+ if (inp) CODA_FREE(inp, insize);
EXIT;
return -error;
}
@@ -89,19 +110,20 @@ ENTRY;
int venus_setattr(struct super_block *sb, struct ViceFid *fid,
struct coda_vattr *vattr)
{
- struct inputArgs *inp;
- struct outputArgs *outp;
- int error, size;
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
- UPARG(vcsize, CFS_SETATTR);
+ insize= SIZE(setattr);
+ UPARG(CFS_SETATTR);
- inp->d.cfs_setattr.VFid = *fid;
- inp->d.cfs_setattr.attr = *vattr;
+ inp->cfs_setattr.VFid = *fid;
+ inp->cfs_setattr.attr = *vattr;
- error = coda_upcall(coda_sbp(sb), vcsize, &size, inp);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
- CDEBUG(D_SUPER, " result %ld\n", outp->result);
- if ( inp ) CODA_FREE(inp, vcsize);
+ CDEBUG(D_SUPER, " result %d\n", error);
+ if ( inp ) CODA_FREE(inp, insize);
return -error;
}
@@ -109,26 +131,26 @@ int venus_lookup(struct super_block *sb, struct ViceFid *fid,
const char *name, int length, int * type,
struct ViceFid *resfid)
{
- struct inputArgs *inp;
- struct outputArgs *outp;
- int insize, size, error=0, payload_offset;
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
+ int offset;
- insize = VC_INSIZE(cfs_lookup_in) + CFS_MAXNAMLEN +1;
- UPARG(insize, CFS_LOOKUP);
+ offset = INSIZE(lookup);
+ insize = max(offset + length +1, OUTSIZE(lookup));
+ UPARG(CFS_LOOKUP);
- inp->d.cfs_lookup.VFid = *fid;
+ inp->cfs_lookup.VFid = *fid;
+ inp->cfs_lookup.name = offset;
/* send Venus a null terminated string */
- payload_offset = VC_INSIZE(cfs_lookup_in);
- inp->d.cfs_lookup.name = (char *) payload_offset;
- memcpy((char *)inp + payload_offset, name, length);
- *((char *)inp + payload_offset + length) = '\0';
+ memcpy((char *)(inp) + offset, name, length);
+ *((char *)inp + offset + length) = '\0';
- size = payload_offset + length + 1;
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if ( !error ) {
- *resfid = outp->d.cfs_lookup.VFid;
- *type = outp->d.cfs_lookup.vtype;
+ *resfid = outp->cfs_lookup.VFid;
+ *type = outp->cfs_lookup.vtype;
}
if (inp) CODA_FREE(inp, insize);
@@ -138,53 +160,48 @@ int venus_lookup(struct super_block *sb, struct ViceFid *fid,
int venus_release(struct super_block *sb, struct ViceFid *fid, int flags)
{
- struct inputArgs *inp;
- struct outputArgs *outp;
- int size = sizeof(struct outputArgs);
- int error = 0;
-
- CODA_ALLOC(inp, struct inputArgs *, sizeof(struct inputArgs));
- outp = (struct outputArgs *)inp;
- INIT_IN(inp, CFS_CLOSE);
- coda_load_creds(&(inp->cred));
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
+
+ insize = SIZE(close);
+ UPARG(CFS_CLOSE);
- inp->d.cfs_close.VFid = *fid;
- inp->d.cfs_close.flags = flags;
+ inp->cfs_close.VFid = *fid;
+ inp->cfs_close.flags = flags;
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
- if (inp) CODA_FREE(inp, sizeof(struct inputArgs));
+ if (inp)
+ CODA_FREE(inp, insize);
return -error;
}
int venus_open(struct super_block *sb, struct ViceFid *fid,
int flags, ino_t *ino, dev_t *dev)
{
- struct inputArgs *inp = NULL;
- struct outputArgs *outp = NULL;
- int size = sizeof(struct inputArgs);
- int error = 0;
-
- CODA_ALLOC(inp, struct inputArgs *, sizeof(struct inputArgs));
- outp = (struct outputArgs *)inp;
- INIT_IN(inp, CFS_OPEN);
- coda_load_creds(&(inp->cred));
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
+
+ insize = SIZE(open);
+ UPARG(CFS_OPEN);
- inp->d.cfs_open.VFid = *fid;
- inp->d.cfs_open.flags = flags;
+ inp->cfs_open.VFid = *fid;
+ inp->cfs_open.flags = flags;
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if ( !error ) {
- *ino = outp->d.cfs_open.inode;
- *dev = outp->d.cfs_open.dev;
+ *ino = outp->cfs_open.inode;
+ *dev = outp->cfs_open.dev;
} else {
*ino = 0;
*dev = 0;
}
if (inp)
- CODA_FREE(inp, sizeof(struct inputArgs));
+ CODA_FREE(inp, insize);
return -error;
}
@@ -193,69 +210,69 @@ int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid,
const char *name, int length,
struct ViceFid *newfid, struct coda_vattr *attrs)
{
- struct inputArgs *inp;
- struct outputArgs *outp;
- int error=0, size, payload_offset;
-
- payload_offset = VC_INSIZE(cfs_mkdir_in);
- size = CFS_MAXNAMLEN + payload_offset;
- UPARG(size, CFS_MKDIR);
-
- inp->d.cfs_mkdir.VFid = *dirfid;
- inp->d.cfs_mkdir.attr = *attrs;
- inp->d.cfs_mkdir.name = (char *) payload_offset;
-
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
+ int offset;
+
+ offset = INSIZE(mkdir);
+ insize = max(offset + length + 1, OUTSIZE(mkdir));
+ UPARG(CFS_MKDIR);
+
+ inp->cfs_mkdir.VFid = *dirfid;
+ inp->cfs_mkdir.attr = *attrs;
+ inp->cfs_mkdir.name = offset;
/* Venus must get null terminated string */
- memcpy((char *)inp + payload_offset, name, length);
- *((char *)inp + payload_offset + length) = '\0';
- size = payload_offset + length + 1;
+ memcpy((char *)(inp) + offset, name, length);
+ *((char *)inp + offset + length) = '\0';
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
- *attrs = outp->d.cfs_mkdir.attr;
- *newfid = outp->d.cfs_mkdir.VFid;
+ *attrs = outp->cfs_mkdir.attr;
+ *newfid = outp->cfs_mkdir.VFid;
if (inp)
- CODA_FREE(inp, size);
+ CODA_FREE(inp, insize);
return -error;
}
int venus_rename(struct super_block *sb, struct ViceFid *old_fid,
struct ViceFid *new_fid, size_t old_length,
- size_t new_length, const char *old_name, const char *new_name)
+ size_t new_length, const char *old_name,
+ const char *new_name)
{
- struct inputArgs *inp;
- struct outputArgs *outp;
- int error, offset, size, s;
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
+ int offset, s;
- size = 2*CFS_MAXNAMLEN + VC_INSIZE(cfs_rename_in) +8;
- UPARG(size, CFS_RENAME);
-
- inp->d.cfs_rename.sourceFid = *old_fid;
- inp->d.cfs_rename.destFid = *new_fid;
+ offset = INSIZE(rename);
+ insize = max(offset + new_length + old_length + 8,
+ OUTSIZE(rename));
+ UPARG(CFS_RENAME);
- offset = VC_INSIZE(cfs_rename_in);
+ inp->cfs_rename.sourceFid = *old_fid;
+ inp->cfs_rename.destFid = *new_fid;
+ inp->cfs_rename.srcname = offset;
/* Venus must receive an null terminated string */
- inp->d.cfs_rename.srcname = (char *)offset;
s = ( old_length & ~0x3) +4; /* round up to word boundary */
- memcpy((char *)inp + offset, old_name, old_length);
+ memcpy((char *)(inp) + offset, old_name, old_length);
*((char *)inp + offset + old_length) = '\0';
/* another null terminated string for Venus */
offset += s;
- inp->d.cfs_rename.destname = (char *)offset;
+ inp->cfs_rename.destname = offset;
s = ( new_length & ~0x3) +4; /* round up to word boundary */
- memcpy((char *)inp + offset, new_name, new_length);
+ memcpy((char *)(inp) + offset, new_name, new_length);
*((char *)inp + offset + new_length) = '\0';
- size += s;
CDEBUG(D_INODE, "destname in packet: %s\n",
- (char *)inp + (int) inp->d.cfs_rename.destname);
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+ (char *)inp + (int) inp->cfs_rename.destname);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
- if (inp) CODA_FREE(inp, size);
+ if (inp) CODA_FREE(inp, insize);
return -error;
}
@@ -263,131 +280,138 @@ int venus_create(struct super_block *sb, struct ViceFid *dirfid,
const char *name, int length, int excl, int mode,
struct ViceFid *newfid, struct coda_vattr *attrs)
{
- struct inputArgs *inp;
- struct outputArgs *outp;
- int error=0, size, payload_offset;
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
+ int offset;
- payload_offset = VC_INSIZE(cfs_create_in);
- size = CFS_MAXNAMLEN + payload_offset;
- UPARG(size, CFS_CREATE);
+ offset = INSIZE(create);
+ insize = max(offset + length + 1, OUTSIZE(create));
+ UPARG(CFS_CREATE);
- inp->d.cfs_create.VFid = *dirfid;
- inp->d.cfs_create.attr.va_mode = mode;
- inp->d.cfs_create.excl = excl;
- inp->d.cfs_create.mode = mode;
- inp->d.cfs_create.name = (char *) payload_offset;
+ inp->cfs_create.VFid = *dirfid;
+ inp->cfs_create.attr.va_mode = mode;
+ inp->cfs_create.excl = excl;
+ inp->cfs_create.mode = mode;
+ inp->cfs_create.name = offset;
/* Venus must get null terminated string */
- memcpy((char *)inp + payload_offset, name, length);
- *((char *)inp + payload_offset + length) = '\0';
- size = payload_offset + length + 1;
-
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+ memcpy((char *)(inp) + offset, name, length);
+ *((char *)inp + offset + length) = '\0';
+
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
- *attrs = outp->d.cfs_create.attr;
- *newfid = outp->d.cfs_create.VFid;
+ *attrs = outp->cfs_create.attr;
+ *newfid = outp->cfs_create.VFid;
if (inp)
- CODA_FREE(inp, size);
+ CODA_FREE(inp, insize);
return -error;
}
int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid,
const char *name, int length)
{
- struct inputArgs *inp;
- struct outputArgs *outp;
- int error=0, size, payload_offset;
-
- payload_offset = VC_INSIZE(cfs_rmdir_in);
- size = CFS_MAXNAMLEN + payload_offset;
- UPARG(size, CFS_RMDIR);
-
- inp->d.cfs_rmdir.VFid = *dirfid;
- inp->d.cfs_rmdir.name = (char *) payload_offset;
- memcpy((char *)inp + payload_offset, name, size);
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
+ int offset;
+
+ offset = INSIZE(rmdir);
+ insize = max(offset + length + 1, OUTSIZE(rmdir));
+ UPARG(CFS_RMDIR);
+
+ inp->cfs_rmdir.VFid = *dirfid;
+ inp->cfs_rmdir.name = offset;
+ memcpy((char *)(inp) + offset, name, length);
+ *((char *)inp + offset + length) = '\0';
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if ( inp )
- CODA_FREE(inp, size);
+ CODA_FREE(inp, insize);
return -error;
}
int venus_remove(struct super_block *sb, struct ViceFid *dirfid,
const char *name, int length)
{
- struct inputArgs *inp;
- struct outputArgs *outp;
- int error=0, size, payload_offset;
-
- payload_offset = VC_INSIZE(cfs_remove_in);
- size = CFS_MAXNAMLEN + payload_offset;
- UPARG(size, CFS_REMOVE);
-
- inp->d.cfs_remove.VFid = *dirfid;
- inp->d.cfs_remove.name = (char *)payload_offset;
- memcpy((char *)inp + payload_offset, name, size);
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int error=0, insize, outsize, offset;
+
+ offset = INSIZE(remove);
+ insize = max(offset + length + 1, OUTSIZE(remove));
+ UPARG(CFS_REMOVE);
+
+ inp->cfs_remove.VFid = *dirfid;
+ inp->cfs_remove.name = offset;
+ memcpy((char *)(inp) + offset, name, length);
+ *((char *)inp + offset + length) = '\0';
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if ( inp )
- CODA_FREE(inp, size);
+ CODA_FREE(inp, insize);
return -error;
}
int venus_readlink(struct super_block *sb, struct ViceFid *fid,
char *buffer, int *length)
{
- int error, size, retlen;
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
+ int retlen;
char *result;
- struct inputArgs *inp;
- struct outputArgs *outp;
- char *buf=NULL; /*[CFS_MAXNAMLEN + VC_INSIZE(cfs_readlink_in)];*/
- size = CFS_MAXPATHLEN + VC_INSIZE(cfs_readlink_in);
- UPARG(size, CFS_READLINK);
- inp->d.cfs_readlink.VFid = *fid;
+ insize = max(INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
+ UPARG(CFS_READLINK);
+
+ inp->cfs_readlink.VFid = *fid;
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if (! error) {
- retlen = outp->d.cfs_readlink.count;
+ retlen = outp->cfs_readlink.count;
if ( retlen > *length )
retlen = *length;
*length = retlen;
- result = (char *)outp + (int)outp->d.cfs_readlink.data;
+ result = (char *)outp + (int)outp->cfs_readlink.data;
memcpy(buffer, result, retlen);
+ *(buffer + retlen) = '\0';
}
- if (inp) CODA_FREE(buf, size);
+ if (inp) CODA_FREE(inp, insize);
CDEBUG(D_INODE, " result %d\n",error);
EXIT;
return -error;
}
+
+
int venus_link(struct super_block *sb, struct ViceFid *fid,
struct ViceFid *dirfid, const char *name, int len )
{
- int error, payload_offset, size;
- struct inputArgs *inp;
- struct outputArgs *outp;
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
+ int offset;
- size = CFS_MAXNAMLEN + sizeof(struct inputArgs);
- UPARG(size, CFS_LINK);
+ offset = INSIZE(link);
+ insize = max(offset + len + 1, OUTSIZE(link));
+ UPARG(CFS_LINK);
- payload_offset = (VC_INSIZE(cfs_link_in));
- inp->d.cfs_link.sourceFid = *fid;
- inp->d.cfs_link.destFid = *dirfid;
- inp->d.cfs_link.tname = (char *)payload_offset;
+ inp->cfs_link.sourceFid = *fid;
+ inp->cfs_link.destFid = *dirfid;
+ inp->cfs_link.tname = offset;
/* make sure strings are null terminated */
- memcpy((char *)inp + payload_offset, name, len);
- *((char *)inp + payload_offset + len) = '\0';
- size = payload_offset + len + 1;
+ memcpy((char *)(inp) + offset, name, len);
+ *((char *)inp + offset + len) = '\0';
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if (inp)
- CODA_FREE(inp, size);
+ CODA_FREE(inp, insize);
CDEBUG(D_INODE, " result %d\n",error);
EXIT;
return -error;
@@ -397,62 +421,73 @@ int venus_symlink(struct super_block *sb, struct ViceFid *fid,
const char *name, int len,
const char *symname, int symlen)
{
- int error, payload_offset, size, s;
- struct inputArgs *inp;
- struct outputArgs *outp;
-
-
- /*
- * allocate space for regular input,
- * plus 1 path and 1 name, plus padding
- */
- size = sizeof(struct inputArgs) + CFS_MAXNAMLEN + CFS_MAXNAMLEN + 8;
- UPARG(size, CFS_SYMLINK);
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
+ int offset, s;
+
+ offset = INSIZE(symlink);
+ insize = max(offset + len + symlen + 8, OUTSIZE(symlink));
+ UPARG(CFS_SYMLINK);
- /* inp->d.cfs_symlink.attr = *tva; XXXXXX */
- inp->d.cfs_symlink.VFid = *fid;
-
- payload_offset = VC_INSIZE(cfs_symlink_in);
- inp->d.cfs_symlink.srcname =(char*) payload_offset;
-
- s = ( symlen & ~0x3 ) + 4; /* Round up to word boundary. */
-
- /* don't forget to copy out the null termination */
- memcpy((char *)inp + payload_offset, symname, symlen);
- *((char *)inp + payload_offset + symlen) = '\0';
+ /* inp->cfs_symlink.attr = *tva; XXXXXX */
+ inp->cfs_symlink.VFid = *fid;
+
+ /* Round up to word boundary and null terminate */
+ inp->cfs_symlink.srcname = offset;
+ s = ( symlen & ~0x3 ) + 4;
+ memcpy((char *)(inp) + offset, symname, symlen);
+ *((char *)inp + offset + symlen) = '\0';
- payload_offset += s;
- inp->d.cfs_symlink.tname = (char *) payload_offset;
- s = (len & ~0x3) + 4; /* Round up to word boundary. */
- memcpy((char *)inp + payload_offset, name, len);
- *((char *)inp + payload_offset + len) = '\0';
+ /* Round up to word boundary and null terminate */
+ offset += s;
+ inp->cfs_symlink.tname = offset;
+ s = (len & ~0x3) + 4;
+ memcpy((char *)(inp) + offset, name, len);
+ *((char *)inp + offset + len) = '\0';
- size = payload_offset + s;
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if (inp)
- CODA_FREE(inp, size);
+ CODA_FREE(inp, insize);
CDEBUG(D_INODE, " result %d\n",error);
EXIT;
return -error;
}
+int venus_fsync(struct super_block *sb, struct ViceFid *fid)
+{
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
+
+ insize=SIZE(fsync);
+ UPARG(CFS_FSYNC);
+
+ inp->cfs_fsync.VFid = *fid;
+ error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
+ &outsize, inp);
+
+ if ( inp )
+ CODA_FREE(inp, insize);
+ return -error;
+}
+
int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
{
- struct inputArgs *inp;
- struct outputArgs *outp;
- int size;
- int error;
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
- size = sizeof(struct inputArgs);
- UPARG(size, CFS_ACCESS);
+ insize = SIZE(access);
+ UPARG(CFS_ACCESS);
- inp->d.cfs_access.VFid = *fid;
- inp->d.cfs_access.flags = mask << 6;
+ inp->cfs_access.VFid = *fid;
+ inp->cfs_access.flags = mask;
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
- if (inp) CODA_FREE(inp, sizeof(struct inputArgs));
+ if (inp) CODA_FREE(inp, insize);
EXIT;
return -error;
}
@@ -461,66 +496,80 @@ int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
unsigned int cmd, struct PioctlData *data)
{
- struct inputArgs *inp;
- struct outputArgs *outp;
- int size, error = 0;
+ union inputArgs *inp;
+ union outputArgs *outp;
+ int insize, outsize, error;
int iocsize;
char str[50];
- size = VC_MAXMSGSIZE;
- UPARG(size, CFS_IOCTL);
+ insize = VC_MAXMSGSIZE;
+ UPARG(CFS_IOCTL);
/* build packet for Venus */
- if (data->vi.in_size > VC_DATASIZE) {
+ if (data->vi.in_size > VC_MAXDATASIZE) {
error = EINVAL;
goto exit;
}
- inp->d.cfs_ioctl.VFid = *fid;
+ inp->cfs_ioctl.VFid = *fid;
/* the cmd field was mutated by increasing its size field to
* reflect the path and follow args. We need to subtract that
* out before sending the command to Venus. */
- inp->d.cfs_ioctl.cmd = (cmd & ~(IOCPARM_MASK << 16));
- iocsize = ((cmd >> 16) & IOCPARM_MASK) - sizeof(char *) - sizeof(int);
- inp->d.cfs_ioctl.cmd |= (iocsize & IOCPARM_MASK) << 16;
+ inp->cfs_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
+ iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
+ inp->cfs_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
- /* in->d.cfs_ioctl.rwflag = flag; */
- inp->d.cfs_ioctl.len = data->vi.in_size;
- inp->d.cfs_ioctl.data = (char *)(VC_INSIZE(cfs_ioctl_in));
+ /* in->cfs_ioctl.rwflag = flag; */
+ inp->cfs_ioctl.len = data->vi.in_size;
+ inp->cfs_ioctl.data = (char *)(INSIZE(ioctl));
/* get the data out of user space */
- if ( copy_from_user((char*)inp + (int)inp->d.cfs_ioctl.data,
+#ifdef L20
+ memcpy_fromfs((char*)inp + (int)inp->cfs_ioctl.data,
+ data->vi.in, data->vi.in_size);
+#else
+ if ( copy_from_user((char*)inp + (int)inp->cfs_ioctl.data,
data->vi.in, data->vi.in_size) ) {
error = EINVAL;
goto exit;
}
- error = coda_upcall(coda_sbp(sb), size, &size, inp);
+#endif
+ error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if (error) {
printk("coda_pioctl: Venus returns: %d for %s\n",
- error, coda_f2s(fid, str));
+ error, coda_f2s(fid));
goto exit;
}
/* Copy out the OUT buffer. */
- if (outp->d.cfs_ioctl.len > data->vi.out_size) {
+ if (outp->cfs_ioctl.len > data->vi.out_size) {
CDEBUG(D_FILE, "return len %d <= request len %d\n",
- outp->d.cfs_ioctl.len,
+ outp->cfs_ioctl.len,
data->vi.out_size);
error = EINVAL;
} else {
- if (copy_to_user(data->vi.out,
- (char *)outp + (int)outp->d.cfs_ioctl.data,
+ error = verify_area(VERIFY_WRITE, data->vi.out,
+ data->vi.out_size);
+ if ( error ) goto exit;
+#ifdef L20
+ memcpy_tofs(data->vi.out,
+ (char *)outp + (int)outp->cfs_ioctl.data,
+ data->vi.out_size);
+#else
+ if (copy_to_user(data->vi.out,
+ (char *)outp + (int)outp->cfs_ioctl.data,
data->vi.out_size)) {
error = EINVAL;
goto exit;
}
+#endif
}
exit:
if (inp)
- CODA_FREE(inp, VC_MAXMSGSIZE);
+ CODA_FREE(inp, insize);
return -error;
}
@@ -535,11 +584,53 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
* reply and return Venus' error, also POSITIVE.
*
*/
+static inline void coda_waitfor_upcall(struct vmsg *vmp)
+{
+ struct wait_queue wait = { current, NULL };
+ old_sigset_t pending;
+
+ vmp->vm_posttime = jiffies;
+
+ add_wait_queue(&vmp->vm_sleep, &wait);
+ for (;;) {
+ if ( coda_hard == 0 )
+ current->state = TASK_INTERRUPTIBLE;
+ else
+ current->state = TASK_UNINTERRUPTIBLE;
+
+ /* got a reply */
+ if ( vmp->vm_flags & VM_WRITE )
+ break;
+
+ if ( ! signal_pending(current) )
+ schedule();
+ /* signal is present: after timeout always return */
+ if ( jiffies > vmp->vm_posttime + coda_timeout * HZ )
+ break;
+
+ spin_lock_irq(&current->sigmask_lock);
+ pending = current->blocked.sig[0] & current->signal.sig[0];
+ spin_unlock_irq(&current->sigmask_lock);
+
+ /* if this process really wants to die, let it go */
+ if ( sigismember(&pending, SIGKILL) ||
+ sigismember(&pending, SIGINT) )
+ break;
+ else
+ schedule();
+ }
+ remove_wait_queue(&vmp->vm_sleep, &wait);
+ current->state = TASK_RUNNING;
+
+ return;
+}
+
+
int coda_upcall(struct coda_sb_info *sbi, int inSize, int *outSize,
- struct inputArgs *buffer)
+ union inputArgs *buffer)
{
struct vcomm *vcommp;
- struct outputArgs *out;
+ union outputArgs *out;
struct vmsg *vmp;
int error = 0;
@@ -550,7 +641,7 @@ ENTRY;
}
vcommp = sbi->sbi_vcomm;
- clstats(((struct inputArgs *)buffer)->opcode);
+ clstats(((union inputArgs *)buffer)->ih.opcode);
if (!vcomm_open(vcommp))
return(ENODEV);
@@ -561,16 +652,15 @@ ENTRY;
vmp->vm_flags = 0;
vmp->vm_inSize = inSize;
vmp->vm_outSize = *outSize ? *outSize : inSize;
- vmp->vm_opcode = ((struct inputArgs *)buffer)->opcode;
+ vmp->vm_opcode = ((union inputArgs *)buffer)->ih.opcode;
vmp->vm_unique = ++vcommp->vc_seq;
vmp->vm_sleep = NULL;
/* Fill in the common input args. */
- ((struct inputArgs *)buffer)->unique = vmp->vm_unique;
+ ((union inputArgs *)buffer)->ih.unique = vmp->vm_unique;
/* Append msg to pending queue and poke Venus. */
-
- INSQUE(vmp->vm_chain, vcommp->vc_pending);
+ coda_q_insert(&(vmp->vm_chain), &(vcommp->vc_pending));
CDEBUG(D_UPCALL,
"Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %x.zzz.\n",
current->pid, vmp->vm_opcode, vmp->vm_unique, (int)vmp);
@@ -582,13 +672,15 @@ ENTRY;
* read but before the reply, we dequeue, send a signal
* message, and return. If it occurs after the reply we ignore
* it. In no case do we want to restart the syscall. If it
- * was interrupted by a venus shutdown (vcclose), return
+ * was interrupted by a venus shutdown (psdev_close), return
* ENODEV. */
- /* Ignore return, We have to check anyway */
-
+ /* Go to sleep. Wake up on signals only after the timeout. */
+ coda_waitfor_upcall(vmp);
- interruptible_sleep_on(&vmp->vm_sleep);
+ CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
+ vmp->vm_opcode, jiffies - vmp->vm_posttime,
+ vmp->vm_unique, vmp->vm_outSize);
CDEBUG(D_UPCALL,
"..process %d woken up by Venus for vmp at 0x%x, data at %x\n",
current->pid, (int)vmp, (int)vmp->vm_data);
@@ -596,60 +688,61 @@ ENTRY;
/* Op went through, interrupt or not... */
if (vmp->vm_flags & VM_WRITE) {
error = 0;
- out = (struct outputArgs *)vmp->vm_data;
- error = out->result;
+ out = (union outputArgs *)vmp->vm_data;
+ error = out->oh.result;
CDEBUG(D_UPCALL,
- "upcall: (u,o,r) (%ld, %ld, %ld) out at %x\n",
- out->unique, out->opcode, out->result, (int)out);
+ "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n",
+ out->oh.unique, out->oh.opcode, out->oh.result, out);
*outSize = vmp->vm_outSize;
goto exit;
- }
- if (!(vmp->vm_flags & VM_READ)) {
+ }
+ if ( !(vmp->vm_flags & VM_READ) && signal_pending(current)) {
/* Interrupted before venus read it. */
CDEBUG(D_UPCALL,
"Interrupted before read:(op,un) (%d.%d), flags = %x\n",
vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags);
- REMQUE(vmp->vm_chain);
- error = ERESTARTSYS;
+ coda_q_remove(&(vmp->vm_chain));
+ error = ERESTARTNOHAND;
goto exit;
}
- if ( vmp->vm_flags & VM_READ) {
+ if ( (vmp->vm_flags & VM_READ) && signal_pending(current) ) {
/* interrupted after Venus did its read, send signal */
- struct inputArgs *dog;
+ union inputArgs *dog;
struct vmsg *svmp;
CDEBUG(D_UPCALL,
"Sending Venus a signal: op = %d.%d, flags = %x\n",
vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags);
- REMQUE(vmp->vm_chain);
- error = ERESTARTSYS;
+ coda_q_remove(&(vmp->vm_chain));
+ error = ERESTARTNOHAND;
CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
- CODA_ALLOC((svmp->vm_data), char *, VC_IN_NO_DATA);
+ CODA_ALLOC((svmp->vm_data), char *, sizeof(struct cfs_in_hdr));
+ dog = (union inputArgs *)svmp->vm_data;
+ dog->ih.opcode = CFS_SIGNAL;
+ dog->ih.unique = vmp->vm_unique;
+
+ svmp->vm_flags = 0;
+ svmp->vm_opcode = dog->ih.opcode;
+ svmp->vm_unique = dog->ih.unique;
+ svmp->vm_inSize = sizeof(struct cfs_in_hdr);
+ svmp->vm_outSize = sizeof(struct cfs_in_hdr);
CDEBUG(D_UPCALL,
"coda_upcall: enqueing signal msg (%d, %d)\n",
svmp->vm_opcode, svmp->vm_unique);
- dog = (struct inputArgs *)svmp->vm_data;
- dog->opcode = CFS_SIGNAL;
- dog->unique = vmp->vm_unique;
-
- svmp->vm_flags = 0;
- svmp->vm_opcode = dog->opcode;
- svmp->vm_unique = dog->unique;
- svmp->vm_inSize = VC_IN_NO_DATA;
- svmp->vm_outSize = VC_IN_NO_DATA;
/* insert at head of queue! */
- INSQUE(svmp->vm_chain, vcommp->vc_pending);
+ coda_q_insert(&(svmp->vm_chain), vcommp->vc_pending.forw);
wake_up_interruptible(&vcommp->vc_waitq);
+ } else {
+ printk("Coda: Strange interruption..\n");
+ error = EINTR;
}
} else { /* If venus died i.e. !VC_OPEN(vcommp) */
- printk("coda_upcall: Venus dead upon (op,un) (%d.%d) flags %d\n",
+ printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags);
-
- /* if (! (vmp->vm_flags & VM_WRITE) ) */
error = ENODEV;
}
@@ -670,78 +763,106 @@ ENTRY;
* CFS_FLUSH -- flush all entries from the name cache and the cnode cache.
* CFS_PURGEUSER -- flush all entries from the name cache for a specific user
* This call is a result of token expiration.
- * Linux does a cfsnc_flush since cred's are not maintained.
*
* The next arise as the result of callbacks on a file or directory.
* CFS_ZAPDIR -- flush the attributes for the dir from its cnode.
* Zap all children of this directory from the namecache.
* CFS_ZAPFILE -- flush the cached attributes for a file.
- * CFS_ZAPVNODE -- in linux the same as zap file (no creds).
+ * CFS_ZAPVNODE -- intended to be a zapfile for just one cred. Not used?
*
* The next is a result of Venus detecting an inconsistent file.
* CFS_PURGEFID -- flush the attribute for the file
- * If it is a dir (odd vnode), purge its
- * children from the namecache
- * remove the file from the namecache.
+ * purge it and its children from the dcache
*
* The last allows Venus to replace local fids with global ones
* during reintegration.
*
* CFS_REPLACE -- replace one ViceFid with another throughout the name cache */
-int coda_downcall(int opcode, struct outputArgs * out)
+int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
{
/* Handle invalidate requests. */
switch (opcode) {
- case CFS_FLUSH : {
- clstats(CFS_FLUSH);
- cfsnc_flush();
- return(0);
- }
- case CFS_PURGEUSER : {
- clstats(CFS_PURGEUSER);
- cfsnc_flush();
- return(0);
- }
- case CFS_ZAPDIR : {
- ViceFid *fid = &out->d.cfs_zapdir.CodaFid;
- clstats(CFS_ZAPDIR);
- cfsnc_zapfid(fid);
- cfsnc_zapParentfid(fid);
- CDEBUG(D_UPCALL, "zapdir: fid = (%lx.%lx.%lx), \n",fid->Volume,
- fid->Vnode,
- fid->Unique);
- return(0);
- }
- case CFS_ZAPVNODE : {
- clstats(CFS_ZAPVNODE);
- cfsnc_zapfid(&out->d.cfs_zapvnode.VFid);
- return(0);
- }
- case CFS_ZAPFILE : {
- clstats(CFS_ZAPFILE);
- cfsnc_zapfid(&out->d.cfs_zapfile.CodaFid);
- return 0;
- }
- case CFS_PURGEFID : {
- ViceFid *fid = &out->d.cfs_purgefid.CodaFid;
- clstats(CFS_PURGEFID);
- cfsnc_zapfid(fid);
- cfsnc_zapParentfid(fid);
- CDEBUG(D_UPCALL, "purgefid: fid = (%lx.%lx.%lx)\n",
- fid->Volume, fid->Vnode,
- fid->Unique);
- return 0;
- }
- case CFS_REPLACE : {
- clstats(CFS_REPLACE);
- cfsnc_replace(&out->d.cfs_replace.OldFid,
- &out->d.cfs_replace.NewFid);
- return (0);
- }
+ case CFS_FLUSH : {
+ clstats(CFS_FLUSH);
+ CDEBUG(D_DOWNCALL, "CFS_FLUSH\n");
+ coda_cache_clear_all(sb);
+ shrink_dcache_sb(sb);
+ return(0);
+ }
+ case CFS_PURGEUSER : {
+ struct coda_cred *cred = &out->cfs_purgeuser.cred;
+ CDEBUG(D_DOWNCALL, "CFS_PURGEUSER\n");
+ if ( !cred ) {
+ printk("PURGEUSER: null cred!\n");
+ return 0;
+ }
+ clstats(CFS_PURGEUSER);
+ coda_cache_clear_cred(sb, cred);
+ return(0);
+ }
+ case CFS_ZAPDIR : {
+ ViceFid *fid = &out->cfs_zapdir.CodaFid;
+ char str[50];
+ if ( !fid ) {
+ printk("ZAPDIR: Null fid\n");
+ return 0;
+ }
+ CDEBUG(D_DOWNCALL, "zapdir: fid = %s\n", coda_f2s(fid));
+ clstats(CFS_ZAPDIR);
+ coda_zapfid(fid, sb, C_ZAPDIR);
+ return(0);
+ }
+ case CFS_ZAPVNODE : {
+ ViceFid *fid = &out->cfs_zapvnode.VFid;
+ char str[50];
+ struct coda_cred *cred = &out->cfs_zapvnode.cred;
+ if ( !fid || !cred ) {
+ printk("ZAPVNODE: Null fid or cred\n");
+ return 0;
+ }
+ CDEBUG(D_DOWNCALL, "zapvnode: fid = %s\n", coda_f2s(fid));
+ coda_zapfid(fid, sb, C_ZAPFID);
+ coda_cache_clear_cred(sb, cred);
+ clstats(CFS_ZAPVNODE);
+ return(0);
+ }
+ case CFS_ZAPFILE : {
+ struct ViceFid *fid = &out->cfs_zapfile.CodaFid;
+ char str[50];
+ clstats(CFS_ZAPFILE);
+ if ( !fid ) {
+ printk("ZAPFILE: Null fid\n");
+ return 0;
+ }
+ CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
+ coda_zapfid(fid, sb, C_ZAPFID);
+ return 0;
+ }
+ case CFS_PURGEFID : {
+ ViceFid *fid = &out->cfs_purgefid.CodaFid;
+ char str[50];
+ if ( !fid ) {
+ printk("PURGEFID: Null fid\n");
+ return 0;
+ }
+ CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
+ clstats(CFS_PURGEFID);
+ coda_zapfid(fid, sb, C_ZAPDIR);
+ return 0;
+ }
+ case CFS_REPLACE : {
+ printk("CFS_REPLACCE\n");
+ clstats(CFS_REPLACE);
+ CDEBUG(D_DOWNCALL, "CFS_REPLACE\n");
+ coda_cache_clear_all(sb);
+ shrink_dcache_sb(sb);
+ return (0);
+ }
}
return 0;
}
+