summaryrefslogtreecommitdiffstats
path: root/fs/coda
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-18 17:17:51 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-18 17:17:51 +0000
commitf1382dc4850bb459d24a81c6cb0ef93ea7bd4a79 (patch)
tree225271a3d5dcd4e9dea5ee393556abd754c964b1 /fs/coda
parent135b00fc2e90e605ac2a96b20b0ebd93851a3f89 (diff)
o Merge with Linux 2.1.90.
o Divide L1 cache sizes by 1024 before printing, makes the numbers a bit more credible ...
Diffstat (limited to 'fs/coda')
-rw-r--r--fs/coda/Makefile2
-rw-r--r--fs/coda/cache.c196
-rw-r--r--fs/coda/cnode.c59
-rw-r--r--fs/coda/coda_linux.c23
-rw-r--r--fs/coda/dir.c104
-rw-r--r--fs/coda/file.c49
-rw-r--r--fs/coda/inode.c (renamed from fs/coda/super.c)35
-rw-r--r--fs/coda/psdev.c4
-rw-r--r--fs/coda/upcall.c55
9 files changed, 315 insertions, 212 deletions
diff --git a/fs/coda/Makefile b/fs/coda/Makefile
index 0a4140745..1f2d0a94c 100644
--- a/fs/coda/Makefile
+++ b/fs/coda/Makefile
@@ -3,7 +3,7 @@
#
O_TARGET := coda.o
-O_OBJS := psdev.o cache.o cnode.o super.o dir.o file.o upcall.o coda_linux.o\
+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
M_OBJS := $(O_TARGET)
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 7673bfbdd..cdf586507 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -24,16 +24,22 @@
#include <linux/coda_fs_i.h>
#include <linux/coda_cache.h>
-/* Keep various stats */
-struct cfsnc_statistics cfsnc_stat;
+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);
+static void coda_ccremove(struct coda_cache *el);
+static void coda_cnremove(struct coda_cache *el);
+static void coda_cache_create(struct inode *inode, int mask);
+static struct coda_cache * coda_cache_find(struct inode *inode);
-/* we need to call INIT_LIST_HEAD on cnp->c_cnhead and sbi->sbi_cchead */
+/* Keep various stats */
+struct cfsnc_statistics cfsnc_stat;
-void coda_ccinsert(struct coda_cache *el, struct super_block *sb)
+/* insert a acl-cache entry in sb list */
+static void coda_ccinsert(struct coda_cache *el, struct super_block *sb)
{
struct coda_sb_info *sbi = coda_sbp(sb);
-ENTRY;
+ ENTRY;
if ( !sbi || !el) {
printk("coda_ccinsert: NULL sbi or el!\n");
return ;
@@ -42,17 +48,19 @@ ENTRY;
list_add(&el->cc_cclist, &sbi->sbi_cchead);
}
-void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cnp)
+/* insert a acl-cache entry in the inode list */
+static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii)
{
-ENTRY;
- if ( !cnp || !el) {
- printk("coda_cninsert: NULL cnp or el!\n");
+ ENTRY;
+ if ( !cii || !el) {
+ printk("coda_cninsert: NULL cii or el!\n");
return ;
}
- list_add(&el->cc_cnlist, &cnp->c_cnhead);
+ list_add(&el->cc_cnlist, &cii->c_cnhead);
}
-void coda_ccremove(struct coda_cache *el)
+/* remove a cache entry from the superblock list */
+static void coda_ccremove(struct coda_cache *el)
{
ENTRY;
if (el->cc_cclist.next && el->cc_cclist.prev)
@@ -61,7 +69,8 @@ void coda_ccremove(struct coda_cache *el)
printk("coda_cnremove: trying to remove 0 entry!");
}
-void coda_cnremove(struct coda_cache *el)
+/* 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)
@@ -70,10 +79,10 @@ void coda_cnremove(struct coda_cache *el)
printk("coda_cnremove: trying to remove 0 entry!");
}
-
-void coda_cache_create(struct inode *inode, int mask)
+/* create a new cache entry and enlist it */
+static void coda_cache_create(struct inode *inode, int mask)
{
- struct coda_inode_info *cnp = ITOC(inode);
+ struct coda_inode_info *cii = ITOC(inode);
struct super_block *sb = inode->i_sb;
struct coda_cache *cc = NULL;
ENTRY;
@@ -85,17 +94,19 @@ void coda_cache_create(struct inode *inode, int mask)
}
coda_load_creds(&cc->cc_cred);
cc->cc_mask = mask;
- coda_cninsert(cc, cnp);
+ coda_cninsert(cc, cii);
coda_ccinsert(cc, sb);
}
-struct coda_cache * coda_cache_find(struct inode *inode)
+/* see if there is a match for the current
+ credentials already */
+static struct coda_cache * coda_cache_find(struct inode *inode)
{
- struct coda_inode_info *cnp = ITOC(inode);
+ struct coda_inode_info *cii = ITOC(inode);
struct list_head *lh, *le;
struct coda_cache *cc = NULL;
- le = lh = &cnp->c_cnhead;
+ le = lh = &cii->c_cnhead;
while( (le = le->next ) != lh ) {
/* compare name and creds */
cc = list_entry(le, struct coda_cache, cc_cnlist);
@@ -107,6 +118,7 @@ struct coda_cache * coda_cache_find(struct inode *inode)
return NULL;
}
+/* create or extend an acl cache hit */
void coda_cache_enter(struct inode *inode, int mask)
{
struct coda_cache *cc;
@@ -120,17 +132,21 @@ void coda_cache_enter(struct inode *inode, int mask)
}
}
-void coda_cache_clear_cnp(struct coda_inode_info *cnp)
+/* remove all cached acl matches from an inode */
+void coda_cache_clear_inode(struct inode *inode)
{
struct list_head *lh, *le;
+ struct coda_inode_info *cii;
struct coda_cache *cc;
+ ENTRY;
- if ( !cnp ) {
- printk("coda_cache_cnp_clear: NULL cnode\n");
+ if ( !inode ) {
+ CDEBUG(D_CACHE, "coda_cache_clear_inode: NULL inode\n");
return;
}
+ cii = ITOC(inode);
- lh = le = &cnp->c_cnhead;
+ lh = le = &cii->c_cnhead;
while ( (le = le->next ) != lh ) {
cc = list_entry(le, struct coda_cache, cc_cnlist);
coda_cnremove(cc);
@@ -139,6 +155,7 @@ void coda_cache_clear_cnp(struct coda_inode_info *cnp)
}
}
+/* remove all acl caches */
void coda_cache_clear_all(struct super_block *sb)
{
struct list_head *lh, *le;
@@ -150,6 +167,9 @@ void coda_cache_clear_all(struct super_block *sb)
return;
}
+ if ( list_empty(&sbi->sbi_cchead) )
+ return;
+
lh = le = &sbi->sbi_cchead;
while ( (le = le->next ) != lh ) {
cc = list_entry(le, struct coda_cache, cc_cclist);
@@ -159,6 +179,7 @@ void coda_cache_clear_all(struct super_block *sb)
}
}
+/* remove all acl caches for a principal */
void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred)
{
struct list_head *lh, *le;
@@ -170,6 +191,9 @@ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred)
return;
}
+ if (list_empty(&sbi->sbi_cchead))
+ return;
+
lh = le = &sbi->sbi_cchead;
while ( (le = le->next ) != lh ) {
cc = list_entry(le, struct coda_cache, cc_cclist);
@@ -180,15 +204,17 @@ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred)
}
}
}
-
+
+/* check if the mask has been matched against the acl
+ already */
int coda_cache_check(struct inode *inode, int mask)
{
- struct coda_inode_info *cnp = ITOC(inode);
+ struct coda_inode_info *cii = ITOC(inode);
struct list_head *lh, *le;
struct coda_cache *cc = NULL;
- le = lh = &cnp->c_cnhead;
+ le = lh = &cii->c_cnhead;
while( (le = le->next ) != lh ) {
/* compare name and creds */
cc = list_entry(le, struct coda_cache, cc_cnlist);
@@ -204,110 +230,70 @@ int coda_cache_check(struct inode *inode, int mask)
}
-/* DENTRY related stuff */
+/* DCACHE & ZAPPING 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)
+/* 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
+ - an inode method coda_revalidate (for attributes) if the
+ flag is C_ATTR
+*/
+static void coda_flag_children(struct dentry *parent, int flag)
{
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));
-
+ coda_flag_inode(de->d_inode, flag);
+ CDEBUG(D_CACHE, "%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);
}
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)
+void coda_flag_alias_children(struct inode *inode, int flag)
{
- cnp->c_flags |= flags;
- coda_cache_clear_cnp(cnp);
+ struct list_head *alias;
+ struct dentry *alias_de;
+
+ if ( !inode )
+ return;
+ 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;
+ }
}
-
-
-/* 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)
+void coda_flag_inode(struct inode *inode, int flag)
{
- struct inode *inode = NULL;
- struct coda_inode_info *cnp;
+ struct coda_inode_info *cii;
- ENTRY;
-
- if ( !sb ) {
- printk("coda_zapfid: no sb!\n");
+ if ( !inode ) {
+ CDEBUG(D_CACHE, " no inode!\n");
return;
}
+ cii = ITOC(inode);
+ cii->c_flags |= flag;
+}
- 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)
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index 67133f275..aa67a22e4 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -15,8 +15,6 @@ extern int coda_print_entry;
/* cnode.c */
-
-
static void coda_fill_inode (struct inode *inode, struct coda_vattr *attr)
{
CDEBUG(D_SUPER, "ino: %ld\n", inode->i_ino);
@@ -56,8 +54,8 @@ 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 ) {
@@ -79,7 +77,7 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb)
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_flags = 0;
cnp->c_vnode = *inode;
INIT_LIST_HEAD(&(cnp->c_cnhead));
INIT_LIST_HEAD(&(cnp->c_volrootlist));
@@ -111,20 +109,51 @@ inline int coda_fideq(ViceFid *fid1, ViceFid *fid2)
-/* convert a fid to an inode. Avoids having a hash table
- such as present in the Mach minicache */
+/* convert a fid to an inode. Mostly we can compute
+ the inode number from the FID, but not for volume
+ mount points: those are in a list */
struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
{
ino_t nr;
struct inode *inode;
struct coda_inode_info *cnp;
-ENTRY;
+ ENTRY;
CDEBUG(D_INODE, "%s\n", coda_f2s(fid));
+ if ( !sb ) {
+ printk("coda_fid_to_inode: no sb!\n");
+ return NULL;
+ }
+
+ if ( !fid ) {
+ printk("coda_fid_to_inode: no fid!\n");
+ return NULL;
+ }
+
+
+ if ( coda_fid_is_volroot(fid) ) {
+ struct coda_inode_info *cii;
+ struct list_head *lh, *le;
+ struct coda_sb_info *sbi = coda_sbp(sb);
+ le = lh = &sbi->sbi_volroothead;
+
+ while ( (le = le->next) != lh ) {
+ cii = list_entry(le, struct coda_inode_info,
+ c_volrootlist);
+ if ( cii->c_fid.Volume == fid->Volume) {
+ inode = cii->c_vnode;
+ CDEBUG(D_INODE, "volume root, found %ld\n", cii->c_vnode->i_ino);
+ return cii->c_vnode;
+ }
+
+ }
+ return NULL;
+ }
+
+ /* fid is not volume root, hence ino is computable */
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);
@@ -133,19 +162,25 @@ ENTRY;
/* check if this inode is linked to a cnode */
cnp = ITOC(inode);
-
if ( cnp->c_magic != CODA_CNODE_MAGIC ) {
+ CDEBUG(D_INODE, "uninitialized inode. Return.\n");
iput(inode);
return NULL;
}
- /* make sure fid is the one we want */
- if ( !coda_fideq(fid, &(cnp->c_fid)) ) {
+ /* make sure fid is the one we want;
+ unfortunately Venus will shamelessly send us mount-symlinks.
+ 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");
iput(inode);
return NULL;
}
+ CDEBUG(D_INODE, "found %ld\n", inode->i_ino);
iput(inode);
return inode;
}
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index e968f3add..4fe096df9 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -32,14 +32,15 @@ int coda_access_cache = 1;
/* caller must allocate 36 byte string ! */
char * coda_f2s(ViceFid *f)
{
- static char s[50];
+ static char s[60];
if ( f ) {
- sprintf(s, "(%10lx,%10lx,%10lx)",
+ sprintf(s, "(%-#lx,%-#lx,%-#lx)",
f->Volume, f->Vnode, f->Unique);
}
return s;
}
+/* recognize special .CONTROL name */
int coda_iscontrol(const char *name, size_t length)
{
if ((CFS_CONTROLLEN == length) &&
@@ -48,16 +49,23 @@ int coda_iscontrol(const char *name, size_t length)
return 0;
}
+/* recognize /coda inode */
int coda_isroot(struct inode *i)
{
if ( i->i_sb->s_root->d_inode == i ) {
- return 1;
+ return 1;
} else {
- return 0;
+ return 0;
}
}
-
+/* is this a volume root FID */
+int coda_fid_is_volroot(struct ViceFid *fid)
+{
+ return ( (fid->Vnode == 1) && (fid->Unique == 1 ) );
+}
+
+/* put the current process credentials in the cred */
void coda_load_creds(struct coda_cred *cred)
{
cred->cr_uid = (vuid_t) current->uid;
@@ -98,11 +106,6 @@ unsigned short coda_flags_to_cflags(unsigned short flags)
}
-int coda_fid_is_volroot(struct ViceFid *fid)
-{
- return ( (fid->Vnode == 1) && (fid->Unique == 1 ) );
-}
-
/* utility functions below */
void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
{
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index dd20499dc..8fed69242 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -40,17 +40,21 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
/* dir file-ops */
static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
+/* dentry ops */
+int coda_dentry_revalidate(struct dentry *de);
+
/* 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);
struct dentry_operations coda_dentry_operations =
{
- NULL, /* revalidate */
+ coda_dentry_revalidate, /* revalidate */
NULL, /* hash */
NULL,
- coda_dentry_delete
+ NULL,
};
struct inode_operations coda_dir_inode_operations =
@@ -74,7 +78,7 @@ struct inode_operations coda_dir_inode_operations =
coda_permission, /* permission */
NULL, /* smap */
NULL, /* update page */
- NULL /* revalidate */
+ coda_revalidate_inode /* revalidate */
};
struct file_operations coda_dir_operations = {
@@ -117,7 +121,6 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
}
dircnp = ITOC(dir);
- CHECK_CNODE(dircnp);
if ( length > CFS_MAXNAMLEN ) {
printk("name too long: lookup, %s (%*s)\n",
@@ -141,9 +144,13 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
(const char *)name, length, &type, &resfid);
res_inode = NULL;
- if (!error || (error == -CFS_NOCACHE) ) {
- if (error == -CFS_NOCACHE)
+ if (!error) {
+ if (type & CFS_NOCACHE) {
+ type &= (~CFS_NOCACHE);
+ CDEBUG(D_INODE, "dropme set for %s\n",
+ coda_f2s(&resfid));
dropme = 1;
+ }
error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
if (error)
return -error;
@@ -152,7 +159,7 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
coda_f2s(&dircnp->c_fid), length, name, error);
return error;
}
- CDEBUG(D_INODE, "lookup: %s is (%s) type %d result %d, dropme %d\n",
+ CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n",
name, coda_f2s(&resfid), type, error, dropme);
exit:
@@ -228,7 +235,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
CHECK_CNODE(dircnp);
if ( length > CFS_MAXNAMLEN ) {
- char str[50];
printk("name too long: create, %s(%s)\n",
coda_f2s(&dircnp->c_fid), name);
return -ENAMETOOLONG;
@@ -238,7 +244,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
0, mode, &newfid, &attrs);
if ( error ) {
- char str[50];
CDEBUG(D_INODE, "create: %s, result %d\n",
coda_f2s(&newfid), error);
d_drop(de);
@@ -321,7 +326,6 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
const char * name = de->d_name.name;
int len = de->d_name.len;
struct coda_inode_info *dir_cnp, *cnp;
- char str[50];
int error;
ENTRY;
@@ -408,7 +412,6 @@ int coda_unlink(struct inode *dir, struct dentry *de)
int error;
const char *name = de->d_name.name;
int len = de->d_name.len;
- char fidstr[50];
ENTRY;
@@ -781,3 +784,82 @@ exit:
CODA_FREE(buff, size);
return error;
}
+
+int coda_dentry_revalidate(struct dentry *de)
+{
+ int valid = 1;
+ struct inode *inode = de->d_inode;
+ struct coda_inode_info *cii;
+ ENTRY;
+
+ if (inode) {
+ if (is_bad_inode(inode))
+ return 0;
+ cii = ITOC(de->d_inode);
+ if (cii->c_flags & C_PURGE)
+ valid = 0;
+ }
+ return valid || coda_isroot(de->d_inode);
+}
+
+
+static int coda_refresh_inode(struct dentry *dentry)
+{
+ struct coda_vattr attr;
+ int error;
+ int old_mode;
+ 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
+ - it's ino changed
+ */
+ old_mode = inode->i_mode;
+ old_ino = inode->i_ino;
+ coda_vattr_to_iattr(inode, &attr);
+
+ if ((inode->i_ino != old_ino) ||
+ ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT))) {
+ make_bad_inode(inode);
+ inode->i_mode = old_mode;
+ return -EIO;
+ }
+
+ cii->c_flags &= ~C_VATTR;
+ return 0;
+}
+
+
+/*
+ * This is called when we want to check if the inode has
+ * changed on the server. Coda makes this easy since the
+ * cache manager Venus issues a downcall to the kernel when this
+ * happens
+ */
+
+int coda_revalidate_inode(struct dentry *dentry)
+{
+ int error = 0;
+ struct coda_inode_info *cii = ITOC(dentry->d_inode);
+
+ ENTRY;
+ CDEBUG(D_INODE, "revalidating: %*s/%*s\n",
+ 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 )) {
+ error = coda_refresh_inode(dentry);
+ }
+
+ return error;
+}
+
diff --git a/fs/coda/file.c b/fs/coda/file.c
index b33680cc3..ae1dd9776 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -30,7 +30,7 @@ static ssize_t coda_file_read(struct file *f, char *buf, size_t count, loff_t *o
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 */
+/* also exported from this file (used for dirs) */
int coda_fsync(struct file *, struct dentry *dentry);
struct inode_operations coda_file_inode_operations = {
@@ -43,7 +43,7 @@ struct inode_operations coda_file_inode_operations = {
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
- NULL, /* rename */
+ NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
coda_readpage, /* readpage */
@@ -53,7 +53,7 @@ struct inode_operations coda_file_inode_operations = {
coda_permission, /* permission */
NULL, /* smap */
NULL, /* update page */
- NULL /* revalidate */
+ coda_revalidate_inode /* revalidate */
};
struct file_operations coda_file_operations = {
@@ -74,41 +74,47 @@ struct file_operations coda_file_operations = {
};
/* File file operations */
-static int coda_readpage(struct file * file, struct page * page)
+static int coda_readpage(struct file * coda_file, struct page * page)
{
- struct dentry *de = file->f_dentry;
- struct inode *inode = de->d_inode;
+ struct dentry *de = coda_file->f_dentry;
+ struct inode *coda_inode = de->d_inode;
struct dentry cont_dentry;
- struct inode *cont_inode;
- struct coda_inode_info *cnp;
+ struct file cont_file;
+ struct coda_inode_info *cii;
ENTRY;
- cnp = ITOC(inode);
- CHECK_CNODE(cnp);
+ cii = ITOC(coda_inode);
- if ( ! cnp->c_ovp ) {
- printk("coda_readpage: no open inode for ino %ld\n", inode->i_ino);
+ if ( ! cii->c_ovp ) {
+ printk("coda_readpage: no open inode for ino %ld, %s\n",
+ coda_inode->i_ino, de->d_name.name);
return -ENXIO;
}
+
+ coda_prepare_openfile(coda_inode, coda_file, cii->c_ovp,
+ &cont_file, &cont_dentry);
- 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, cont_inode->i_ino, page->offset);
+ CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n",
+ coda_inode->i_ino, cii->c_ovp->i_ino, page->offset);
- generic_readpage(&cont_dentry, page);
+ generic_readpage(&cont_file, page);
EXIT;
return 0;
}
static int coda_file_mmap(struct file * file, struct vm_area_struct * vma)
{
- struct coda_inode_info *cnp;
- cnp = ITOC(file->f_dentry->d_inode);
- cnp->c_mmcount++;
+ struct coda_inode_info *cii;
+ int res;
+
+ ENTRY;
+ cii = ITOC(file->f_dentry->d_inode);
+ cii->c_mmcount++;
- return generic_file_mmap(file, vma);
+ res =generic_file_mmap(file, vma);
+ EXIT;
+ return res;
}
static ssize_t coda_file_read(struct file *coda_file, char *buff,
@@ -120,7 +126,6 @@ static ssize_t coda_file_read(struct file *coda_file, char *buff,
struct file cont_file;
struct dentry cont_dentry;
int result = 0;
-
ENTRY;
cnp = ITOC(coda_inode);
diff --git a/fs/coda/super.c b/fs/coda/inode.c
index 5410fb50d..96d07e265 100644
--- a/fs/coda/super.c
+++ b/fs/coda/inode.c
@@ -4,7 +4,7 @@
* 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>
+ * Rewritten for Linux 2.1. Peter Braam <braam@cs.cmu.edu>
* Copyright (C) Carnegie Mellon University
*/
@@ -81,7 +81,6 @@ static struct super_block * coda_read_super(struct super_block *sb,
ViceFid fid;
kdev_t dev = sb->s_dev;
int error;
- char str[50];
ENTRY;
MOD_INC_USE_COUNT;
@@ -180,10 +179,10 @@ static void coda_put_super(struct super_block *sb)
/* all filling in of inodes postponed until lookup */
static void coda_read_inode(struct inode *inode)
{
- struct coda_inode_info *cnp;
+ struct coda_inode_info *cii;
ENTRY;
- cnp = ITOC(inode);
- cnp->c_magic = 0;
+ cii = ITOC(inode);
+ cii->c_magic = 0;
return;
}
@@ -200,32 +199,32 @@ static void coda_put_inode(struct inode *in)
static void coda_delete_inode(struct inode *inode)
{
- struct coda_inode_info *cnp;
+ struct coda_inode_info *cii;
struct inode *open_inode;
ENTRY;
CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n",
inode->i_ino, inode->i_count);
- cnp = ITOC(inode);
- if ( inode->i_ino == CTL_INO || cnp->c_magic != CODA_CNODE_MAGIC ) {
+ cii = ITOC(inode);
+ if ( inode->i_ino == CTL_INO || cii->c_magic != CODA_CNODE_MAGIC ) {
clear_inode(inode);
return;
}
- if ( coda_fid_is_volroot(&cnp->c_fid) )
- list_del(&cnp->c_volrootlist);
+ if ( coda_fid_is_volroot(&cii->c_fid) )
+ list_del(&cii->c_volrootlist);
- open_inode = cnp->c_ovp;
+ open_inode = cii->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;
+ cii->c_ovp = NULL;
iput(open_inode);
}
- coda_cache_clear_cnp(cnp);
+ coda_cache_clear_inode(inode);
inode->u.generic_ip = NULL;
clear_inode(inode);
@@ -235,24 +234,24 @@ static void coda_delete_inode(struct inode *inode)
static int coda_notify_change(struct dentry *de, struct iattr *iattr)
{
struct inode *inode = de->d_inode;
- struct coda_inode_info *cnp;
+ struct coda_inode_info *cii;
struct coda_vattr vattr;
int error;
ENTRY;
memset(&vattr, 0, sizeof(vattr));
- cnp = ITOC(inode);
- CHECK_CNODE(cnp);
+ cii = ITOC(inode);
+ CHECK_CNODE(cii);
coda_iattr_to_vattr(iattr, &vattr);
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);
+ error = venus_setattr(inode->i_sb, &cii->c_fid, &vattr);
if ( !error ) {
coda_vattr_to_iattr(inode, &vattr);
- coda_cache_clear_cnp(cnp);
+ coda_cache_clear_inode(inode);
}
CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n",
inode->i_mode, error);
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 04333e046..119d14f51 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -65,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 */
-unsigned long coda_timeout = 10; /* .. secs, then signals will dequeue */
+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];
@@ -447,7 +447,7 @@ 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");
+ printk(KERN_INFO "Coda Kernel/User communications module 2.0\n");
status = init_coda_psdev();
if ( status ) {
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index ac625ad17..13d3127c6 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -500,7 +500,6 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
union outputArgs *outp;
int insize, outsize, error;
int iocsize;
- char str[50];
insize = VC_MAXMSGSIZE;
UPARG(CFS_IOCTL);
@@ -587,7 +586,6 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid,
static inline void coda_waitfor_upcall(struct vmsg *vmp)
{
struct wait_queue wait = { current, NULL };
- old_sigset_t pending;
vmp->vm_posttime = jiffies;
@@ -608,13 +606,9 @@ static inline void coda_waitfor_upcall(struct vmsg *vmp)
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) )
+ if ( sigismember(&current->signal, SIGKILL) ||
+ sigismember(&current->signal, SIGINT) )
break;
else
schedule();
@@ -765,10 +759,14 @@ ENTRY;
* This call is a result of token expiration.
*
* 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 -- intended to be a zapfile for just one cred. Not used?
+
+ * CFS_ZAPDIR -- flush the attributes for the dir and
+ * 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
@@ -803,53 +801,48 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
return(0);
}
case CFS_ZAPDIR : {
+ struct inode *inode;
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);
+ 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;
- 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);
+ 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;
- 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);
+ inode = coda_fid_to_inode(fid, sb);
+ coda_flag_inode(inode, C_PURGE);
+ coda_cache_clear_inode(inode);
return 0;
}
case CFS_REPLACE : {