summaryrefslogtreecommitdiffstats
path: root/fs/coda
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
commitc7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch)
tree3682407a599b8f9f03fc096298134cafba1c9b2f /fs/coda
parent1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff)
o Merge with Linux 2.1.116.
o New Newport console code. o New G364 console code.
Diffstat (limited to 'fs/coda')
-rw-r--r--fs/coda/Makefile4
-rw-r--r--fs/coda/cache.c117
-rw-r--r--fs/coda/cnode.c53
-rw-r--r--fs/coda/coda_linux.c64
-rw-r--r--fs/coda/dir.c244
-rw-r--r--fs/coda/file.c5
-rw-r--r--fs/coda/inode.c10
-rw-r--r--fs/coda/pioctl.c6
-rw-r--r--fs/coda/psdev.c105
-rw-r--r--fs/coda/upcall.c348
10 files changed, 601 insertions, 355 deletions
diff --git a/fs/coda/Makefile b/fs/coda/Makefile
index 4e6c40dce..8dd3fa6d1 100644
--- a/fs/coda/Makefile
+++ b/fs/coda/Makefile
@@ -1,5 +1,5 @@
#
-# Makefile for the linux Coda-filesystem routines.
+# Makefile for the Linux Coda filesystem routines.
#
O_TARGET := coda.o
@@ -7,7 +7,7 @@ O_OBJS := psdev.o cache.o cnode.o inode.o dir.o file.o upcall.o coda_linux.o\
symlink.o pioctl.o sysctl.o stats.o
M_OBJS := $(O_TARGET)
-# If you want debugging output, please uncomment the following line
+# If you want debugging output, please uncomment the following line.
# EXTRA_CFLAGS += -DDEBUG -DDEBUG_SMB_MALLOC=1
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 1285ac757..946e88758 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -37,8 +37,10 @@ static 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");
+ /* third test verifies cc was initialized before adding it
+ to the sblist. Probably superfluous */
+ if ( !sbi || !el || !list_empty(&el->cc_cclist) ) {
+ printk("coda_ccinsert: NULL sbi or el->cc_cclist not empty!\n");
return ;
}
@@ -49,8 +51,8 @@ static void coda_ccinsert(struct coda_cache *el, struct super_block *sb)
static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii)
{
ENTRY;
- if ( !cii || !el) {
- printk("coda_cninsert: NULL cii or el!\n");
+ if ( !cii || !el || ! list_empty(&el->cc_cnlist)) {
+ printk("coda_cninsert: NULL cii or el->cc_cnlist not empty!\n");
return ;
}
list_add(&el->cc_cnlist, &cii->c_cnhead);
@@ -60,20 +62,20 @@ static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii)
static void coda_ccremove(struct coda_cache *el)
{
ENTRY;
- if (el->cc_cclist.next && el->cc_cclist.prev)
+ if ( ! list_empty(&el->cc_cclist) )
list_del(&el->cc_cclist);
else
- printk("coda_cnremove: trying to remove 0 entry!");
+ printk("coda_cnremove: loose cc entry!");
}
/* remove a cache entry from the inode's list */
static void coda_cnremove(struct coda_cache *el)
{
ENTRY;
- if (el->cc_cnlist.next && el->cc_cnlist.prev)
+ if ( ! list_empty(&el->cc_cnlist) )
list_del(&el->cc_cnlist);
else
- printk("coda_cnremove: trying to remove 0 entry!");
+ printk("coda_cnremove: loose cn entry!");
}
/* create a new cache entry and enlist it */
@@ -83,12 +85,17 @@ static void coda_cache_create(struct inode *inode, int mask)
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;
}
+
+ INIT_LIST_HEAD(&cc->cc_cclist);
+ INIT_LIST_HEAD(&cc->cc_cnlist);
+
coda_load_creds(&cc->cc_cred);
cc->cc_mask = mask;
coda_cninsert(cc, cii);
@@ -227,15 +234,58 @@ int coda_cache_check(struct inode *inode, int mask)
}
-/* DCACHE & ZAPPING related stuff */
+/* Purging dentries and children */
+/* The following routines drop dentries which are not
+ in use and flag dentries which are in use to be
+ zapped later.
-/* the following routines set flags in the inodes. They are
- detected by:
- - a dentry method: coda_dentry_revalidate (for lookups)
- if the flag is C_PURGE
+ The flags are detected by:
+ - coda_dentry_revalidate (for lookups) if the flag is C_PURGE
+ - coda_dentry_delete: to remove dentry from the cache when d_count
+ falls to zero
- an inode method coda_revalidate (for attributes) if the
- flag is C_ATTR
+ flag is C_VATTR
*/
+
+/*
+ Some of this is pretty scary: what can disappear underneath us?
+ - shrink_dcache_parent calls on purge_one_dentry which is safe:
+ it only purges children.
+ - dput is evil since it may recurse up the dentry tree
+ */
+
+void coda_purge_dentries(struct inode *inode)
+{
+ struct list_head *tmp, *head = &inode->i_dentry;
+
+ if (!inode)
+ return ;
+
+ /* better safe than sorry: dput could kill us */
+ iget(inode->i_sb, inode->i_ino);
+ /* catch the dentries later if some are still busy */
+ coda_flag_inode(inode, C_PURGE);
+
+restart:
+ tmp = head;
+ while ((tmp = tmp->next) != head) {
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
+ if (!dentry->d_count) {
+ CDEBUG(D_DOWNCALL,
+ "coda_free_dentries: freeing %s/%s, i_count=%d\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ inode->i_count);
+ dget(dentry);
+ d_drop(dentry);
+ dput(dentry);
+ goto restart;
+ }
+
+ }
+ iput(inode);
+}
+
+/* this won't do any harm: just flag all children */
static void coda_flag_children(struct dentry *parent, int flag)
{
struct list_head *child;
@@ -244,38 +294,44 @@ static void coda_flag_children(struct dentry *parent, int flag)
child = parent->d_subdirs.next;
while ( child != &parent->d_subdirs ) {
de = list_entry(child, struct dentry, d_child);
- coda_flag_inode(de->d_inode, flag);
- CDEBUG(D_CACHE, "%d for %*s/%*s\n", flag,
+ child = child->next;
+ /* don't know what to do with negative dentries */
+ if ( ! de->d_inode )
+ continue;
+ CDEBUG(D_DOWNCALL, "%d for %*s/%*s\n", flag,
de->d_name.len, de->d_name.name,
de->d_parent->d_name.len, de->d_parent->d_name.name);
- child = child->next;
- if ( !de->d_inode )
- d_drop(de);
+ coda_flag_inode(de->d_inode, flag);
}
return;
}
-
-void coda_flag_alias_children(struct inode *inode, int flag)
+void coda_purge_children(struct inode *inode)
{
struct list_head *alias;
struct dentry *alias_de;
if ( !inode )
return;
+
+ if (list_empty(&inode->i_dentry))
+ return;
+
+ /* I believe that shrink_dcache_parent will not
+ remove dentries from the alias list. If it
+ does we are toast.
+ */
alias = inode->i_dentry.next;
while ( alias != &inode->i_dentry ) {
alias_de = list_entry(alias, struct dentry, d_alias);
- if ( !alias_de ) {
- printk("Corrupt alias list for %*s\n",
- alias_de->d_name.len, alias_de->d_name.name);
- return;
- }
- coda_flag_children(alias_de, flag);
- alias= alias->next;
+ coda_flag_children(alias_de, C_PURGE);
+ shrink_dcache_parent(alias_de);
+ alias = alias->next;
}
+
}
+/* this will not zap the inode away */
void coda_flag_inode(struct inode *inode, int flag)
{
struct coda_inode_info *cii;
@@ -284,11 +340,8 @@ void coda_flag_inode(struct inode *inode, int flag)
CDEBUG(D_CACHE, " no inode!\n");
return;
}
+
cii = ITOC(inode);
cii->c_flags |= flag;
}
-
-
-
-
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index aa67a22e4..2f0f86878 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -15,7 +15,7 @@ extern int coda_print_entry;
/* cnode.c */
-static void coda_fill_inode (struct inode *inode, struct coda_vattr *attr)
+static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
{
CDEBUG(D_SUPER, "ino: %ld\n", inode->i_ino);
@@ -30,6 +30,16 @@ static void coda_fill_inode (struct inode *inode, struct coda_vattr *attr)
inode->i_op = &coda_dir_inode_operations;
else if (S_ISLNK(inode->i_mode))
inode->i_op = &coda_symlink_inode_operations;
+ else if (S_ISCHR(inode->i_mode)) {
+ inode->i_op = &chrdev_inode_operations;
+ inode->i_rdev = to_kdev_t(attr->va_rdev);
+ } else if (S_ISBLK(inode->i_mode)) {
+ inode->i_op = &blkdev_inode_operations;
+ inode->i_rdev = to_kdev_t(attr->va_rdev);
+ } else if (S_ISFIFO(inode->i_mode))
+ init_fifo(inode);
+ else if (S_ISSOCK(inode->i_mode))
+ inode->i_op = NULL;
else {
printk ("coda_read_inode: what's this? i_mode = %o\n",
inode->i_mode);
@@ -54,12 +64,12 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
ENTRY;
/*
- * We get inode numbers from Venus -- see venus source
- */
+ * We get inode numbers from Venus -- see venus source
+ */
error = venus_getattr(sb, fid, &attr);
if ( error ) {
- printk("coda_cnode_make: coda_getvattr returned %d for %s.\n",
+ CDEBUG(D_CNODE, "coda_cnode_make: coda_getvattr returned %d for %s.\n",
error, coda_f2s(fid));
*inode = NULL;
return error;
@@ -82,16 +92,26 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
INIT_LIST_HEAD(&(cnp->c_cnhead));
INIT_LIST_HEAD(&(cnp->c_volrootlist));
} else {
- printk("coda_cnode make on initialized inode %ld, %s!\n",
+ cnp->c_flags = 0;
+ CDEBUG(D_CNODE, "coda_cnode make on initialized"
+ "inode %ld, %s!\n",
(*inode)->i_ino, coda_f2s(&cnp->c_fid));
}
/* fill in the inode attributes */
- if ( coda_fid_is_volroot(fid) )
+ if ( coda_f2i(fid) != ino ) {
+ if ( !coda_fid_is_weird(fid) )
+ printk("Coda: unknown weird fid: ino %ld, fid %s."
+ "Tell Peter.\n", ino, coda_f2s(&cnp->c_fid));
list_add(&cnp->c_volrootlist, &sbi->sbi_volroothead);
+ CDEBUG(D_UPCALL, "Added %ld ,%s to volroothead\n",
+ ino, coda_f2s(&cnp->c_fid));
+ }
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);
+ CDEBUG(D_DOWNCALL, "Done making inode: ino %ld, count %d with %s\n",
+ (*inode)->i_ino, (*inode)->i_count,
+ coda_f2s(&cnp->c_fid));
EXIT;
return 0;
@@ -119,7 +139,6 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
struct coda_inode_info *cnp;
ENTRY;
- CDEBUG(D_INODE, "%s\n", coda_f2s(fid));
if ( !sb ) {
printk("coda_fid_to_inode: no sb!\n");
@@ -130,9 +149,10 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
printk("coda_fid_to_inode: no fid!\n");
return NULL;
}
+ CDEBUG(D_INODE, "%s\n", coda_f2s(fid));
- if ( coda_fid_is_volroot(fid) ) {
+ if ( coda_fid_is_weird(fid) ) {
struct coda_inode_info *cii;
struct list_head *lh, *le;
struct coda_sb_info *sbi = coda_sbp(sb);
@@ -141,9 +161,14 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
while ( (le = le->next) != lh ) {
cii = list_entry(le, struct coda_inode_info,
c_volrootlist);
- if ( cii->c_fid.Volume == fid->Volume) {
+ CDEBUG(D_DOWNCALL, "iterating, now doing %s, ino %ld\n",
+ coda_f2s(&cii->c_fid), cii->c_vnode->i_ino);
+ if ( coda_fideq(&cii->c_fid, fid) ) {
inode = cii->c_vnode;
CDEBUG(D_INODE, "volume root, found %ld\n", cii->c_vnode->i_ino);
+ if ( cii->c_magic != CODA_CNODE_MAGIC )
+ printk("%s: Bad magic in inode, tell Peter.\n",
+ __FUNCTION__);
return cii->c_vnode;
}
@@ -151,7 +176,7 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
return NULL;
}
- /* fid is not volume root, hence ino is computable */
+ /* fid is not weird: ino should be computable */
nr = coda_f2i(fid);
inode = iget(sb, nr);
if ( !inode ) {
@@ -173,9 +198,9 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
These have the same inode as the root of the volume they
mount, but the fid will be wrong.
*/
- if ( !coda_fideq(fid, &(cnp->c_fid)) &&
- !coda_fid_is_volroot(&(cnp->c_fid))) {
- printk("coda_fid2inode: bad cnode! Tell Peter.\n");
+ if ( !coda_fideq(fid, &(cnp->c_fid)) ) {
+ /* printk("coda_fid2inode: bad cnode (ino %ld, fid %s)"
+ "Tell Peter.\n", nr, coda_f2s(fid)); */
iput(inode);
return NULL;
}
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index 322b764a9..b7500ed65 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -65,6 +65,36 @@ int coda_fid_is_volroot(struct ViceFid *fid)
{
return ( (fid->Vnode == 1) && (fid->Unique == 1 ) );
}
+
+int coda_fid_is_weird(struct ViceFid *fid)
+{
+ /* volume roots */
+ if ( (fid->Vnode == 1) && (fid->Unique == 1 ) )
+ return 1;
+ /* tmpfid unique (simulate.cc) */
+ if ( fid->Unique == 0xffffffff )
+ return 1;
+ /* LocalFakeVnode (local.h) */
+ if ( fid->Vnode == 0xfffffffd )
+ return 1;
+ /* LocalFileVnode (venus.private.h) */
+ if ( fid->Vnode == 0xfffffffe )
+ return 1;
+ /* local fake vid (local.h) */
+ if ( fid->Volume == 0xffffffff )
+ return 1;
+ /* local DirVnode (venus.private.h) */
+ if ( fid->Vnode == 0xffffffff )
+ return 1;
+ /* FakeVnode (venus.private.h) */
+ if ( fid->Vnode == 0xfffffffc )
+ return 1;
+
+ return 0;
+
+}
+
+
/* put the current process credentials in the cred */
void coda_load_creds(struct coda_cred *cred)
@@ -93,15 +123,31 @@ int coda_cred_eq(struct coda_cred *cred1, struct coda_cred *cred2)
unsigned short coda_flags_to_cflags(unsigned short flags)
{
unsigned short coda_flags = 0;
-
- if ( flags & (O_RDONLY | O_RDWR) )
+
+ if ( (flags & O_ACCMODE) == O_RDONLY ){
+ CDEBUG(D_FILE, "--> C_O_READ added\n");
coda_flags |= C_O_READ;
+ }
+
+ if ( (flags & O_ACCMODE) == O_RDWR ) {
+ CDEBUG(D_FILE, "--> C_O_READ | C_O_WRITE added\n");
+ coda_flags |= C_O_READ | C_O_WRITE;
+ }
- if ( flags & (O_WRONLY | O_RDWR) )
+ if ( (flags & O_ACCMODE) == O_WRONLY ){
+ CDEBUG(D_FILE, "--> C_O_WRITE added\n");
coda_flags |= C_O_WRITE;
+ }
- if ( flags & O_TRUNC )
+ if ( flags & O_TRUNC ) {
+ CDEBUG(D_FILE, "--> C_O_TRUNC added\n");
coda_flags |= C_O_TRUNC;
+ }
+
+ if ( flags & O_EXCL ) {
+ coda_flags |= C_O_EXCL;
+ CDEBUG(D_FILE, "--> C_O_EXCL added\n");
+ }
return coda_flags;
}
@@ -142,12 +188,10 @@ void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
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_blocksize != -1)
+ inode->i_blksize = attr->va_blocksize;
+ if (attr->va_size != -1)
+ inode->i_blocks = (attr->va_size + 511) >> 9;
if (attr->va_atime.tv_sec != -1)
inode->i_atime = attr->va_atime.tv_sec;
if (attr->va_mtime.tv_sec != -1)
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index ba0ec6e2f..fabc4e3c8 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -27,6 +27,7 @@
/* dir inode-ops */
static int coda_create(struct inode *dir, struct dentry *new, int mode);
+static int coda_mknod(struct inode *dir, struct dentry *new, int mode, int rdev);
static int coda_lookup(struct inode *dir, struct dentry *target);
static int coda_link(struct dentry *old_dentry, struct inode *dir_inode,
struct dentry *entry);
@@ -42,20 +43,24 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
/* dentry ops */
-int coda_dentry_revalidate(struct dentry *de);
-
+static int coda_dentry_revalidate(struct dentry *de);
+static void coda_dentry_delete(struct dentry *);
/* support routines */
static int coda_venus_readdir(struct file *filp, void *dirent,
filldir_t filldir);
int coda_fsync(struct file *, struct dentry *dentry);
static int coda_refresh_inode(struct dentry *dentry);
+int coda_crossvol_rename = 0;
+int coda_hasmknod = 0;
+
+
struct dentry_operations coda_dentry_operations =
{
coda_dentry_revalidate, /* revalidate */
NULL, /* hash */
- NULL,
- NULL,
+ NULL, /* compare */
+ coda_dentry_delete /* delete */
};
struct inode_operations coda_dir_inode_operations =
@@ -68,7 +73,7 @@ struct inode_operations coda_dir_inode_operations =
coda_symlink, /* symlink */
coda_mkdir, /* mkdir */
coda_rmdir, /* rmdir */
- NULL, /* mknod */
+ coda_mknod, /* mknod */
coda_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
@@ -118,7 +123,7 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("coda_lookup: inode is NULL or not a directory\n");
- return -ENOENT;
+ return -ENOTDIR;
}
dircnp = ITOC(dir);
@@ -154,7 +159,7 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
}
error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
if (error)
- return -error;
+ return error;
} else if (error != -ENOENT) {
CDEBUG(D_INODE, "error for %s(%*s)%d\n",
coda_f2s(&dircnp->c_fid), length, name, error);
@@ -167,8 +172,10 @@ exit:
entry->d_time = 0;
entry->d_op = &coda_dentry_operations;
d_add(entry, res_inode);
- if ( dropme )
+ if ( dropme ) {
d_drop(entry);
+ ITOC(res_inode)->c_flags |= C_VATTR;
+ }
EXIT;
return 0;
}
@@ -213,7 +220,7 @@ int coda_permission(struct inode *inode, int mask)
-/* creation routines: create, mkdir, link, symlink */
+/* creation routines: create, mknod, mkdir, link, symlink */
static int coda_create(struct inode *dir, struct dentry *de, int mode)
{
@@ -225,6 +232,7 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
struct ViceFid newfid;
struct coda_vattr attrs;
+ ENTRY;
coda_vfs_stat.create++;
CDEBUG(D_INODE, "name: %s, length %d, mode %o\n",name, length, mode);
@@ -247,7 +255,7 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
}
error = venus_create(dir->i_sb, &(dircnp->c_fid), name, length,
- 0, mode, &newfid, &attrs);
+ 0, mode, 0, &newfid, &attrs);
if ( error ) {
CDEBUG(D_INODE, "create: %s, result %d\n",
@@ -264,7 +272,64 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
}
/* invalidate the directory cnode's attributes */
- dircnp->c_flags &= ~C_VATTR;
+ dircnp->c_flags |= C_VATTR;
+ d_instantiate(de, result);
+ return 0;
+}
+
+static int coda_mknod(struct inode *dir, struct dentry *de, int mode, int rdev)
+{
+ int error=0;
+ struct coda_inode_info *dircnp;
+ const char *name=de->d_name.name;
+ int length=de->d_name.len;
+ struct inode *result = NULL;
+ struct ViceFid newfid;
+ struct coda_vattr attrs;
+
+ if ( coda_hasmknod == 0 )
+ return -EIO;
+
+ coda_vfs_stat.create++;
+
+ CDEBUG(D_INODE, "name: %s, length %d, mode %o, rdev %x\n",name, length, mode, rdev);
+
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("coda_mknod: 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 ) {
+ printk("name too long: mknod, %s(%s)\n",
+ coda_f2s(&dircnp->c_fid), name);
+ return -ENAMETOOLONG;
+ }
+
+ error = venus_create(dir->i_sb, &(dircnp->c_fid), name, length,
+ 0, mode, rdev, &newfid, &attrs);
+
+ if ( error ) {
+ CDEBUG(D_INODE, "mknod: %s, result %d\n",
+ 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;
d_instantiate(de, result);
return 0;
}
@@ -279,7 +344,7 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
int error;
struct ViceFid newfid;
-
+ ENTRY;
coda_vfs_stat.mkdir++;
if (!dir || !S_ISDIR(dir->i_mode)) {
@@ -320,7 +385,7 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
}
/* invalidate the directory cnode's attributes */
- dircnp->c_flags &= ~C_VATTR;
+ dircnp->c_flags |= C_VATTR;
dir->i_nlink++;
d_instantiate(de, inode);
return 0;
@@ -343,7 +408,6 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
return -EPERM;
dir_cnp = ITOC(dir_inode);
- CHECK_CNODE(dir_cnp);
cnp = ITOC(inode);
CHECK_CNODE(cnp);
@@ -359,9 +423,10 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
(const char *)name, len);
if ( ! error ) {
- dir_cnp->c_flags &= ~C_VATTR;
- inode->i_nlink++;
+ dir_cnp->c_flags |= C_VATTR;
+ ++inode->i_count;
d_instantiate(de, inode);
+ inode->i_nlink++;
} else {
d_drop(de);
}
@@ -415,7 +480,6 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
}
/* destruction routines: unlink, rmdir */
-
int coda_unlink(struct inode *dir, struct dentry *de)
{
struct coda_inode_info *dircnp;
@@ -442,9 +506,9 @@ int coda_unlink(struct inode *dir, struct dentry *de)
}
/* cache management */
- dircnp->c_flags &= ~C_VATTR;
-
+ dircnp->c_flags |= C_VATTR;
de->d_inode->i_nlink--;
+
d_delete(de);
return 0;
@@ -457,6 +521,7 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
int len = de->d_name.len;
int error, rehash = 0;
+ ENTRY;
coda_vfs_stat.rmdir++;
if (!dir || !S_ISDIR(dir->i_mode)) {
@@ -513,56 +578,58 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *old_inode = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode;
struct coda_inode_info *new_cnp, *old_cnp;
- int error, rehash = 0, update = 1;
-ENTRY;
+ int error;
+
+ ENTRY;
coda_vfs_stat.rename++;
+ if ( (old_length > CFS_MAXNAMLEN) || new_length > CFS_MAXNAMLEN ) {
+ return -ENAMETOOLONG;
+ }
+
old_cnp = ITOC(old_dir);
- CHECK_CNODE(old_cnp);
new_cnp = ITOC(new_dir);
- CHECK_CNODE(new_cnp);
- CDEBUG(D_INODE, "old: %s, (%d length, %d strlen), new: %s (%d length, %d strlen).\n", old_name, old_length, strlen(old_name), new_name, new_length, strlen(new_name));
+ CDEBUG(D_INODE, "old: %s, (%d length, %d strlen), new: %s"
+ "(%d length, %d strlen).old:d_count: %d, new:d_count: %d\n",
+ old_name, old_length, strlen(old_name), new_name, new_length,
+ strlen(new_name),old_dentry->d_count, new_dentry->d_count);
- if ( (old_length > CFS_MAXNAMLEN) || new_length > CFS_MAXNAMLEN ) {
- return -ENAMETOOLONG;
+ if (new_inode == old_inode)
+ return 0;
+
+ /* make sure target is not in use */
+ if (new_inode && S_ISDIR(new_inode->i_mode)) {
+ /*
+ * Prune any children before testing for busy.
+ */
+ if (new_dentry->d_count > 1)
+ shrink_dcache_parent(new_dentry);
+
+ if (new_dentry->d_count > 1)
+ return -EBUSY;
}
- /* 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); */
-
- /* cross directory moves */
- if (new_dir != old_dir &&
- S_ISDIR(old_inode->i_mode) &&
- old_dentry->d_count > 1)
- shrink_dcache_parent(old_dentry);
-
- /* We must prevent any new references to the
- * target while the rename is in progress, so
- * we unhash the dentry. */
- if (!list_empty(&new_dentry->d_hash)) {
- d_drop(new_dentry);
- rehash = 1;
- }
+ /* the C library will do unlink/create etc */
+ if ( coda_crossvol_rename == 0 &&
+ old_cnp->c_fid.Volume != new_cnp->c_fid.Volume )
+ return -EXDEV;
error = venus_rename(old_dir->i_sb, &(old_cnp->c_fid),
&(new_cnp->c_fid), old_length, new_length,
(const char *) old_name, (const char *)new_name);
- if (rehash) {
- d_add(new_dentry, new_inode);
- }
-
if ( error ) {
CDEBUG(D_INODE, "returned error %d\n", error);
return error;
}
- /* Update the dcache if needed */
- if (update)
- d_move(old_dentry, new_dentry);
-
- CDEBUG(D_INODE, "result %d\n", error);
+
+ coda_flag_inode(new_inode, C_VATTR);
+ coda_flag_inode(old_dir, C_VATTR);
+ coda_flag_inode(new_dir, C_VATTR);
+
+ CDEBUG(D_INODE, "result %d\n", error);
+ d_move(old_dentry, new_dentry);
EXIT;
return 0;
@@ -592,7 +659,7 @@ int coda_readdir(struct file *file, void *dirent, filldir_t filldir)
if ( !cnp->c_ovp ) {
CDEBUG(D_FILE, "open inode pointer = NULL.\n");
- return -ENODEV;
+ return -EIO;
}
coda_prepare_openfile(inode, file, cnp->c_ovp, &open_file,
@@ -618,17 +685,16 @@ int coda_open(struct inode *i, struct file *f)
struct coda_inode_info *cnp;
int error = 0;
struct inode *cont_inode = NULL;
- unsigned short flags = f->f_flags;
+ unsigned short flags = f->f_flags & (~O_EXCL);
unsigned short coda_flags = coda_flags_to_cflags(flags);
ENTRY;
coda_vfs_stat.open++;
- CDEBUG(D_SPECIAL, "OPEN inode number: %ld, flags %o.\n",
- f->f_dentry->d_inode->i_ino, flags);
+ CDEBUG(D_SPECIAL, "OPEN inode number: %ld, count %d, flags %o.\n",
+ f->f_dentry->d_inode->i_ino, f->f_dentry->d_count, flags);
cnp = ITOC(i);
- CHECK_CNODE(cnp);
error = venus_open(i->i_sb, &(cnp->c_fid), coda_flags, &ino, &dev);
if (error) {
@@ -639,26 +705,22 @@ int coda_open(struct inode *i, struct file *f)
/* coda_upcall returns ino number of cached object, get inode */
CDEBUG(D_FILE, "cache file dev %d, ino %ld\n", dev, ino);
+ error = coda_inode_grab(dev, ino, &cont_inode);
+
+ if ( error || !cont_inode ){
+ printk("coda_open: coda_inode_grab error %d.", error);
+ if (cont_inode)
+ iput(cont_inode);
+ return error;
+ }
- if ( ! cnp->c_ovp ) {
- error = coda_inode_grab(dev, ino, &cont_inode);
-
- if ( error ){
- printk("coda_open: coda_inode_grab error %d.", error);
- if (cont_inode) iput(cont_inode);
- return error;
- }
- 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;
- }
+ if ( cnp->c_ovp ) {
+ iput(cnp->c_ovp);
+ cnp->c_ovp = NULL;
+ }
+ cnp->c_ovp = cont_inode;
cnp->c_ocount++;
- /* if opened for writing flush cache entry. */
-/* 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);
CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %x\n",
@@ -672,7 +734,7 @@ int coda_release(struct inode *i, struct file *f)
{
struct coda_inode_info *cnp;
int error;
- unsigned short flags = f->f_flags;
+ unsigned short flags = (f->f_flags) & (~O_EXCL);
unsigned short cflags = coda_flags_to_cflags(flags);
ENTRY;
@@ -803,7 +865,8 @@ exit:
return error;
}
-int coda_dentry_revalidate(struct dentry *de)
+/* called when a cache lookup succeeds */
+static int coda_dentry_revalidate(struct dentry *de)
{
int valid = 1;
struct inode *inode = de->d_inode;
@@ -820,6 +883,26 @@ int coda_dentry_revalidate(struct dentry *de)
return valid || coda_isroot(de->d_inode);
}
+/*
+ * This is the callback from dput() when d_count is going to 0.
+ * We use this to unhash dentries with bad inodes.
+ */
+static void coda_dentry_delete(struct dentry * dentry)
+{
+ int flags;
+
+ if (!dentry->d_inode)
+ return ;
+
+ flags = (ITOC(dentry->d_inode)->c_flags) & C_PURGE;
+ if (is_bad_inode(dentry->d_inode) || flags) {
+ CDEBUG(D_DOWNCALL, "bad inode, unhashing %s/%s, %ld\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ dentry->d_inode->i_ino);
+ d_drop(dentry);
+ }
+}
+
static int coda_refresh_inode(struct dentry *dentry)
{
@@ -829,16 +912,17 @@ static int coda_refresh_inode(struct dentry *dentry)
ino_t old_ino;
struct inode *inode = dentry->d_inode;
struct coda_inode_info *cii = ITOC(inode);
-
+
ENTRY;
+
error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
if ( error ) {
make_bad_inode(inode);
return -EIO;
}
- /* this baby may be lost if:
- - it's type changed
+ /* this inode may be lost if:
+ - it's type changed
- it's ino changed
*/
old_mode = inode->i_mode;
@@ -874,7 +958,7 @@ int coda_revalidate_inode(struct dentry *dentry)
dentry->d_name.len, dentry->d_name.name,
dentry->d_parent->d_name.len, dentry->d_parent->d_name.name);
- if ( cii->c_flags & (C_VATTR | C_PURGE )) {
+ if (cii->c_flags & (C_VATTR | C_PURGE)) {
error = coda_refresh_inode(dentry);
}
diff --git a/fs/coda/file.c b/fs/coda/file.c
index c92aeeb27..949d9ce00 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -192,13 +192,14 @@ static ssize_t coda_file_write(struct file *coda_file, const char *buff,
return -1;
}
- cnp->c_flags &= ~C_VATTR;
-
down(&cont_inode->i_sem);
result = cont_file.f_op->write(&cont_file , buff, count,
&(cont_file.f_pos));
up(&cont_inode->i_sem);
coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
+
+ if (result)
+ cnp->c_flags |= C_VATTR;
return result;
}
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 92543a15c..f215ce314 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -48,7 +48,7 @@ static int coda_statfs(struct super_block *sb, struct statfs *buf,
int bufsiz);
/* helper functions */
-static inline struct vcomm *coda_psinode2vcomm(struct inode *inode);
+static struct vcomm *coda_psinode2vcomm(struct inode *inode);
static int coda_get_psdev(void *, struct inode **);
static struct coda_sb_info *coda_psinode2sbi(struct inode *inode);
@@ -161,6 +161,8 @@ static void coda_put_super(struct super_block *sb)
ENTRY;
+
+ sb->s_dev = 0;
coda_cache_clear_all(sb);
sb_info = coda_sbp(sb);
sb_info->sbi_vcomm->vc_inuse = 0;
@@ -209,7 +211,7 @@ static void coda_delete_inode(struct inode *inode)
}
- if ( coda_fid_is_volroot(&cii->c_fid) )
+ if ( ! list_empty(&cii->c_volrootlist) )
list_del(&cii->c_volrootlist);
open_inode = cii->c_ovp;
@@ -221,7 +223,7 @@ static void coda_delete_inode(struct inode *inode)
}
coda_cache_clear_inode(inode);
-
+ CDEBUG(D_DOWNCALL, "clearing inode: %ld, %x\n", inode->i_ino, cii->c_flags);
inode->u.generic_ip = NULL;
clear_inode(inode);
EXIT;
@@ -289,7 +291,7 @@ int init_coda_fs(void)
/* MODULE stuff is in psdev.c */
/* helpers */
-static inline struct vcomm *coda_psinode2vcomm(struct inode *inode)
+static struct vcomm *coda_psinode2vcomm(struct inode *inode)
{
unsigned int minor = MINOR(inode->i_rdev);
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index 99c960f7d..aa143afcf 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -123,7 +123,7 @@ static int coda_pioctl(struct inode * inode, struct file * filp,
target_de = lnamei(data.path);
}
- if ( PTR_ERR(target_de) == -ENOENT ) {
+ if ( IS_ERR(target_de) ) {
CDEBUG(D_PIOCTL, "error: lookup fails.\n");
return PTR_ERR(target_de);
} else {
@@ -142,12 +142,12 @@ static int coda_pioctl(struct inode * inode, struct file * filp,
/* now proceed to make the upcall */
cnp = ITOC(target_inode);
- CHECK_CNODE(cnp);
error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data);
CDEBUG(D_PIOCTL, "ioctl on inode %ld\n", target_inode->i_ino);
-
+ CDEBUG(D_DOWNCALL, "dput on ino: %ld, icount %d, dcount %d\n", target_inode->i_ino,
+ target_inode->i_count, target_de->d_count);
if ( target_de )
dput(target_de);
return error;
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index e3ce5b39f..73fa6ddfe 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -33,6 +33,7 @@
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/poll.h>
+#include <linux/init.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <asm/system.h>
@@ -64,7 +65,7 @@ extern int cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, i
/* statistics */
struct coda_upcallstats coda_callstats;
-int coda_hard = 0; /* introduces a timeout on upcalls */
+int coda_hard = 0; /* allows signals during upcalls */
unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */
extern struct coda_sb_info coda_super_info[MAX_CODADEVS];
struct vcomm psdev_vcomm[MAX_CODADEVS];
@@ -401,23 +402,7 @@ static struct file_operations coda_psdev_fops = {
#ifdef CONFIG_PROC_FS
-struct proc_dir_entry proc_sys_root = {
- PROC_SYS, 3, "sys", /* inode, name */
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0, /* mode, nlink, uid, gid */
- 0, &proc_dir_inode_operations, /* size, ops */
- NULL, NULL, /* get_info, fill_inode */
- NULL, /* next */
- NULL, NULL /* parent, subdir */
-};
-
-struct proc_dir_entry proc_fs_coda = {
- PROC_FS_CODA, 4, "coda",
- S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
- 0, &proc_dir_inode_operations,
- NULL, NULL,
- NULL,
- NULL, NULL
-};
+extern struct proc_dir_entry proc_sys_root;
struct proc_dir_entry proc_sys_coda = {
0, 4, "coda",
@@ -428,8 +413,17 @@ struct proc_dir_entry proc_sys_coda = {
NULL, NULL
};
-struct proc_dir_entry proc_fs = {
- PROC_FS, 2, "fs",
+/*
+ target directory structure:
+ /proc/fs (see linux/fs/proc/root.c)
+ /proc/fs/coda
+ /proc/fs/coda/{vfs_stats,
+
+*/
+
+
+struct proc_dir_entry proc_fs_coda = {
+ PROC_FS_CODA, 4, "coda",
S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
0, &proc_dir_inode_operations,
NULL, NULL,
@@ -437,15 +431,6 @@ struct proc_dir_entry proc_fs = {
NULL, NULL
};
-#if 0
-struct proc_dir_entry proc_coda_ncstats = {
- 0 , 12, "coda-ncstats",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_net_inode_operations,
- cfsnc_nc_info
- };
-#endif
-
struct proc_dir_entry proc_coda_vfs = {
PROC_VFS_STATS , 9, "vfs_stats",
S_IFREG | S_IRUGO, 1, 0, 0,
@@ -504,6 +489,23 @@ struct proc_dir_entry proc_coda_cache_inv_control = {
#endif
+__initfunc(int init_coda(void))
+{
+ int status;
+ printk(KERN_INFO "Coda Kernel/Venus communications, v4.6.0, braam@cs.cmu.edu\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;
+}
int init_coda_psdev(void)
{
@@ -522,15 +524,14 @@ int init_coda_psdev(void)
reset_coda_cache_inv_stats();
#ifdef CONFIG_PROC_FS
- proc_register(&proc_root,&proc_fs);
- proc_register(&proc_fs,&proc_fs_coda);
+ proc_register(&proc_root_fs,&proc_fs_coda);
proc_register(&proc_fs_coda,&proc_coda_vfs);
proc_register(&proc_fs_coda,&proc_coda_upcall);
proc_register(&proc_fs_coda,&proc_coda_permission);
proc_register(&proc_fs_coda,&proc_coda_cache_inv);
-#if 0
- proc_register(&proc_fs_coda, &proc_coda_ncstats);
#endif
+
+#ifdef CONFIG_SYSCTL
proc_register(&proc_sys_root,&proc_sys_coda);
proc_register(&proc_sys_coda,&proc_coda_vfs_control);
proc_register(&proc_sys_coda,&proc_coda_upcall_control);
@@ -551,20 +552,20 @@ MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
int init_module(void)
{
- int status;
- printk(KERN_INFO "Coda Kernel/User communications module 2.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;
+ int status;
+ printk(KERN_INFO "Coda Kernel/Venus communications (module), v4.6.0, braam@cs.cmu.edu\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;
}
@@ -585,18 +586,16 @@ void cleanup_module(void)
proc_unregister(&proc_sys_coda, proc_coda_cache_inv_control.low_ino);
proc_unregister(&proc_sys_coda, proc_coda_permission_control.low_ino);
proc_unregister(&proc_sys_coda, proc_coda_upcall_control.low_ino);
- proc_unregister(&proc_sys_coda,proc_coda_vfs_control.low_ino);
+ proc_unregister(&proc_sys_coda, proc_coda_vfs_control.low_ino);
proc_unregister(&proc_sys_root, proc_sys_coda.low_ino);
-
-#if 0
- proc_unregister(&proc_fs_coda, proc_coda_ncstats.low_ino);
#endif
+
+#ifdef CONFIG_SYSCTL
proc_unregister(&proc_fs_coda, proc_coda_cache_inv.low_ino);
proc_unregister(&proc_fs_coda, proc_coda_permission.low_ino);
proc_unregister(&proc_fs_coda, proc_coda_upcall.low_ino);
proc_unregister(&proc_fs_coda, proc_coda_vfs.low_ino);
- proc_unregister(&proc_fs, proc_fs_coda.low_ino);
- proc_unregister(&proc_root, proc_fs.low_ino);
+ proc_unregister(&proc_root_fs, proc_fs_coda.low_ino);
#endif
}
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 0e3ba95d1..041845e33 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -39,6 +39,8 @@
#include <linux/coda_cache.h>
#include <linux/coda_proc.h>
+extern void coda_purge_dentries(struct inode *inode);
+extern void coda_purge_children(struct inode *inode);
static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
union inputArgs *buffer);
@@ -46,7 +48,8 @@ static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
#define UPARG(op)\
do {\
CODA_ALLOC(inp, union inputArgs *, insize);\
- outp = (union outputArgs *) (inp);\
+ if ( !inp ) { return -ENOMEM; }\
+ outp = (union outputArgs *) (inp);\
inp->ih.opcode = (op);\
inp->ih.pid = current->pid;\
inp->ih.pgid = current->pgrp;\
@@ -90,7 +93,7 @@ int venus_rootfid(struct super_block *sb, ViceFid *fidp)
if (inp) CODA_FREE(inp, insize);
EXIT;
- return -error;
+ return error;
}
int venus_getattr(struct super_block *sb, struct ViceFid *fid,
@@ -98,19 +101,22 @@ int venus_getattr(struct super_block *sb, struct ViceFid *fid,
{
union inputArgs *inp;
union outputArgs *outp;
- int insize, outsize, error;
-ENTRY;
+ int insize, outsize, error;
+ ENTRY;
+
insize = SIZE(getattr);
UPARG(CFS_GETATTR);
inp->cfs_getattr.VFid = *fid;
+
error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if ( !error )
*attr = outp->cfs_getattr.attr;
- if (inp) CODA_FREE(inp, insize);
+ if (inp)
+ CODA_FREE(inp, insize);
EXIT;
- return -error;
+ return error;
}
int venus_setattr(struct super_block *sb, struct ViceFid *fid,
@@ -130,7 +136,7 @@ int venus_setattr(struct super_block *sb, struct ViceFid *fid,
CDEBUG(D_SUPER, " result %d\n", error);
if ( inp ) CODA_FREE(inp, insize);
- return -error;
+ return error;
}
int venus_lookup(struct super_block *sb, struct ViceFid *fid,
@@ -160,7 +166,7 @@ int venus_lookup(struct super_block *sb, struct ViceFid *fid,
}
if (inp) CODA_FREE(inp, insize);
- return -error;
+ return error;
}
@@ -180,7 +186,7 @@ int venus_release(struct super_block *sb, struct ViceFid *fid, int flags)
if (inp)
CODA_FREE(inp, insize);
- return -error;
+ return error;
}
int venus_open(struct super_block *sb, struct ViceFid *fid,
@@ -209,7 +215,7 @@ int venus_open(struct super_block *sb, struct ViceFid *fid,
if (inp)
CODA_FREE(inp, insize);
- return -error;
+ return error;
}
int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid,
@@ -239,7 +245,7 @@ int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid,
if (inp)
CODA_FREE(inp, insize);
- return -error;
+ return error;
}
@@ -279,11 +285,11 @@ int venus_rename(struct super_block *sb, struct ViceFid *old_fid,
error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if (inp) CODA_FREE(inp, insize);
- return -error;
+ return error;
}
int venus_create(struct super_block *sb, struct ViceFid *dirfid,
- const char *name, int length, int excl, int mode,
+ const char *name, int length, int excl, int mode, int rdev,
struct ViceFid *newfid, struct coda_vattr *attrs)
{
union inputArgs *inp;
@@ -297,6 +303,7 @@ int venus_create(struct super_block *sb, struct ViceFid *dirfid,
inp->cfs_create.VFid = *dirfid;
inp->cfs_create.attr.va_mode = mode;
+ inp->cfs_create.attr.va_rdev = rdev;
inp->cfs_create.excl = excl;
inp->cfs_create.mode = mode;
inp->cfs_create.name = offset;
@@ -312,7 +319,7 @@ int venus_create(struct super_block *sb, struct ViceFid *dirfid,
if (inp)
CODA_FREE(inp, insize);
- return -error;
+ return error;
}
int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid,
@@ -335,7 +342,7 @@ int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid,
error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if ( inp )
CODA_FREE(inp, insize);
- return -error;
+ return error;
}
int venus_remove(struct super_block *sb, struct ViceFid *dirfid,
@@ -357,7 +364,7 @@ int venus_remove(struct super_block *sb, struct ViceFid *dirfid,
error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
if ( inp )
CODA_FREE(inp, insize);
- return -error;
+ return error;
}
int venus_readlink(struct super_block *sb, struct ViceFid *fid,
@@ -389,7 +396,7 @@ int venus_readlink(struct super_block *sb, struct ViceFid *fid,
if (inp) CODA_FREE(inp, insize);
CDEBUG(D_INODE, " result %d\n",error);
EXIT;
- return -error;
+ return error;
}
@@ -420,7 +427,7 @@ int venus_link(struct super_block *sb, struct ViceFid *fid,
CODA_FREE(inp, insize);
CDEBUG(D_INODE, " result %d\n",error);
EXIT;
- return -error;
+ return error;
}
int venus_symlink(struct super_block *sb, struct ViceFid *fid,
@@ -458,7 +465,7 @@ int venus_symlink(struct super_block *sb, struct ViceFid *fid,
CODA_FREE(inp, insize);
CDEBUG(D_INODE, " result %d\n",error);
EXIT;
- return -error;
+ return error;
}
int venus_fsync(struct super_block *sb, struct ViceFid *fid)
@@ -476,7 +483,7 @@ int venus_fsync(struct super_block *sb, struct ViceFid *fid)
if ( inp )
CODA_FREE(inp, insize);
- return -error;
+ return error;
}
int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
@@ -495,7 +502,7 @@ int venus_access(struct super_block *sb, struct ViceFid *fid, int mask)
if (inp) CODA_FREE(inp, insize);
EXIT;
- return -error;
+ return error;
}
@@ -575,7 +582,7 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
exit:
if (inp)
CODA_FREE(inp, insize);
- return -error;
+ return error;
}
/*
@@ -583,12 +590,6 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
*
*/
-/*
- * coda_upcall will return a POSITIVE error in the case of
- * failed communication with Venus _or_ will peek at Venus
- * reply and return Venus' error, also POSITIVE.
- *
- */
static inline unsigned long coda_waitfor_upcall(struct vmsg *vmp)
{
struct wait_queue wait = { current, NULL };
@@ -608,18 +609,18 @@ static inline unsigned long coda_waitfor_upcall(struct vmsg *vmp)
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;
-
- /* if this process really wants to die, let it go */
- if ( sigismember(&current->signal, SIGKILL) ||
- sigismember(&current->signal, SIGINT) )
- break;
- else
- schedule();
+ if ( !coda_hard && signal_pending(current) ) {
+ /* if this process really wants to die, let it go */
+ if ( sigismember(&(current->signal), SIGKILL) ||
+ sigismember(&(current->signal), SIGINT) )
+ break;
+ /* signal is present: after timeout always return
+ really smart idea, probably useless ... */
+ if ( jiffies > vmp->vm_posttime + coda_timeout * HZ )
+ break;
+ }
+ schedule();
+
}
remove_wait_queue(&vmp->vm_sleep, &wait);
current->state = TASK_RUNNING;
@@ -630,6 +631,16 @@ static inline unsigned long coda_waitfor_upcall(struct vmsg *vmp)
}
+/*
+ * coda_upcall will return an error in the case of
+ * failed communication with Venus _or_ will peek at Venus
+ * reply and return Venus' error.
+ *
+ * As venus has 2 types of errors, normal errors (positive) and internal
+ * errors (negative), normal errors are negated, while internal errors
+ * are all mapped to -EINTR, while showing a nice warning message. (jh)
+ *
+ */
static int coda_upcall(struct coda_sb_info *sbi,
int inSize, int *outSize,
union inputArgs *buffer)
@@ -643,13 +654,13 @@ static int coda_upcall(struct coda_sb_info *sbi,
ENTRY;
if (sbi->sbi_vcomm == NULL) {
- return ENODEV;
+ return -ENODEV;
}
vcommp = sbi->sbi_vcomm;
if (!vcomm_open(vcommp))
- return(ENODEV);
+ return -ENXIO;
/* Format the request message. */
CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
@@ -693,9 +704,14 @@ ENTRY;
if (vcomm_open(vcommp)) { /* i.e. Venus is still alive */
/* Op went through, interrupt or not... */
if (vmp->vm_flags & VM_WRITE) {
- error = 0;
out = (union outputArgs *)vmp->vm_data;
- error = out->oh.result;
+ /* here we map positive Venus errors to kernel errors */
+ if ( out->oh.result < 0 ) {
+ printk("Tell Peter: Venus returns negative error %ld, for oc %ld!\n",
+ out->oh.result, out->oh.opcode);
+ out->oh.result = EINTR;
+ }
+ error = -out->oh.result;
CDEBUG(D_UPCALL,
"upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n",
out->oh.unique, out->oh.opcode, out->oh.result, out);
@@ -708,48 +724,49 @@ ENTRY;
"Interrupted before read:(op,un) (%d.%d), flags = %x\n",
vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags);
coda_q_remove(&(vmp->vm_chain));
- error = ERESTARTNOHAND;
+ /* perhaps the best way to convince the app to
+ give up? */
+ error = -EINTR;
goto exit;
}
if ( (vmp->vm_flags & VM_READ) && signal_pending(current) ) {
- /* interrupted after Venus did its read, send signal */
- 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);
-
- coda_q_remove(&(vmp->vm_chain));
- error = ERESTARTNOHAND;
-
- CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
- 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);
-
- /* insert at head of queue! */
- coda_q_insert(&(svmp->vm_chain), vcommp->vc_pending.forw);
- wake_up_interruptible(&vcommp->vc_waitq);
+ /* interrupted after Venus did its read, send signal */
+ 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);
+
+ coda_q_remove(&(vmp->vm_chain));
+ error = -EINTR;
+ CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
+ 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);
+
+ /* insert at head of queue! */
+ coda_q_insert(&(svmp->vm_chain), vcommp->vc_pending.forw);
+ wake_up_interruptible(&vcommp->vc_waitq);
} else {
printk("Coda: Strange interruption..\n");
- error = EINTR;
+ error = -EINTR;
}
} else { /* If venus died i.e. !VC_OPEN(vcommp) */
printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags);
- error = ENODEV;
+ error = -ENODEV;
}
exit:
@@ -759,7 +776,13 @@ ENTRY;
return error;
}
-
+/*
+ The statements below are part of the Coda opportunistic
+ programming -- taken from the Mach/BSD kernel code for Coda.
+ You don't get correct semantics by stating what needs to be
+ done without guaranteeing the invariants needed for it to happen.
+ When will be have time to find out what exactly is going on? (pjb)
+*/
/*
@@ -777,8 +800,6 @@ ENTRY;
* force a new lookup for all the children
of this dir.
- * 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
@@ -792,81 +813,98 @@ ENTRY;
int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
{
- /* Handle invalidate requests. */
- switch (opcode) {
- 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 : {
- struct inode *inode;
- ViceFid *fid = &out->cfs_zapdir.CodaFid;
- if ( !fid ) {
- printk("ZAPDIR: Null fid\n");
- return 0;
- }
- CDEBUG(D_DOWNCALL, "zapdir: fid = %s\n", coda_f2s(fid));
- clstats(CFS_ZAPDIR);
- inode = coda_fid_to_inode(fid, sb);
- coda_flag_inode(inode, C_VATTR);
- coda_cache_clear_inode(inode);
- coda_flag_alias_children(inode, C_PURGE);
- return(0);
- }
-
- case CFS_ZAPVNODE :
- case CFS_ZAPFILE : {
- struct inode *inode;
- struct ViceFid *fid = &out->cfs_zapfile.CodaFid;
- clstats(CFS_ZAPFILE);
- if ( !fid ) {
- printk("ZAPFILE: Null fid\n");
- return 0;
- }
- CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
- inode = coda_fid_to_inode(fid, sb);
- coda_flag_inode(inode, C_VATTR);
- coda_cache_clear_inode(inode);
- return 0;
- }
- case CFS_PURGEFID : {
- struct inode *inode;
- ViceFid *fid = &out->cfs_purgefid.CodaFid;
- if ( !fid ) {
- printk("PURGEFID: Null fid\n");
- return 0;
- }
- CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
- clstats(CFS_PURGEFID);
- inode = coda_fid_to_inode(fid, sb);
- coda_flag_inode(inode, C_PURGE);
- coda_cache_clear_inode(inode);
- 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;
+ /* Handle invalidation requests. */
+ if ( !sb ) {
+ printk("coda_downcall: opcode %d, no sb!\n", opcode);
+ return 0;
+ }
+
+ switch (opcode) {
+
+ 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 : {
+ struct inode *inode;
+ ViceFid *fid = &out->cfs_zapdir.CodaFid;
+ CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid));
+ clstats(CFS_ZAPDIR);
+
+ inode = coda_fid_to_inode(fid, sb);
+ if (inode) {
+ CDEBUG(D_DOWNCALL, "zapdir: inode = %ld children flagged\n",
+ inode->i_ino);
+ coda_purge_children(inode);
+ CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino);
+ coda_flag_inode(inode, C_VATTR);
+ } else
+ CDEBUG(D_DOWNCALL, "zapdir: no inode\n");
+
+ return(0);
+ }
+
+ case CFS_ZAPFILE : {
+ struct inode *inode;
+ struct ViceFid *fid = &out->cfs_zapfile.CodaFid;
+ clstats(CFS_ZAPFILE);
+ CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid));
+ inode = coda_fid_to_inode(fid, sb);
+ if ( inode ) {
+ CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n", inode->i_ino);
+ coda_flag_inode(inode, C_VATTR);
+ } else
+ CDEBUG(D_DOWNCALL, "zapfile: no inode\n");
+ return 0;
+ }
+
+ case CFS_PURGEFID : {
+ struct inode *inode;
+ ViceFid *fid = &out->cfs_purgefid.CodaFid;
+ CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid));
+ clstats(CFS_PURGEFID);
+ inode = coda_fid_to_inode(fid, sb);
+ if ( inode ) {
+ CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n", inode->i_ino);
+ coda_purge_children(inode);
+ coda_purge_dentries(inode);
+ }else
+ CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
+ return 0;
+ }
+
+ case CFS_REPLACE : {
+ struct inode *inode;
+ ViceFid *fid = &out->cfs_replace.OldFid;
+ clstats(CFS_REPLACE);
+ CDEBUG(D_DOWNCALL, "CFS_REPLACE\n");
+ inode = coda_fid_to_inode(fid, sb);
+ if ( inode ) {
+ CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n", inode->i_ino);
+ coda_purge_children(inode);
+ coda_purge_dentries(inode);
+ }else
+ CDEBUG(D_DOWNCALL, "purgefid: no inode\n");
+ return 0;
+ }
+ }
+ return 0;
}