diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-06-19 22:45:37 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-06-19 22:45:37 +0000 |
commit | 6d403070f28cd44860fdb3a53be5da0275c65cf4 (patch) | |
tree | 0d0e7fe7b5fb7568d19e11d7d862b77a866ce081 /fs/coda | |
parent | ecf1bf5f6c2e668d03b0a9fb026db7aa41e292e1 (diff) |
Merge with 2.4.0-test1-ac21 + pile of MIPS cleanups to make merging
possible. Chainsawed RM200 kernel to compile again. Jazz machine
status unknown.
Diffstat (limited to 'fs/coda')
-rw-r--r-- | fs/coda/cache.c | 155 | ||||
-rw-r--r-- | fs/coda/cnode.c | 100 | ||||
-rw-r--r-- | fs/coda/dir.c | 342 | ||||
-rw-r--r-- | fs/coda/file.c | 151 | ||||
-rw-r--r-- | fs/coda/inode.c | 75 | ||||
-rw-r--r-- | fs/coda/pioctl.c | 2 | ||||
-rw-r--r-- | fs/coda/psdev.c | 160 | ||||
-rw-r--r-- | fs/coda/stats.c | 416 | ||||
-rw-r--r-- | fs/coda/sysctl.c | 14 | ||||
-rw-r--r-- | fs/coda/upcall.c | 188 |
10 files changed, 516 insertions, 1087 deletions
diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 68be7a69d..eff2da6cd 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c @@ -24,82 +24,48 @@ #include <linux/coda_fs_i.h> #include <linux/coda_cache.h> -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); - - -/* insert a acl-cache entry in sb list */ -static void coda_ccinsert(struct coda_cache *el, struct super_block *sb) +/* create a new acl cache entry and enlist it */ +static struct coda_cache *coda_cache_create(struct inode *inode) { - struct coda_sb_info *sbi = coda_sbp(sb); + struct coda_inode_info *cii = ITOC(inode); + struct coda_sb_info *sbi = coda_sbp(inode->i_sb); + struct coda_cache *cc = NULL; ENTRY; - /* 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 ; + + if ( !sbi || !cii ) { + printk("coda_cache_create: NULL sbi or cii!\n"); + return NULL; } - list_add(&el->cc_cclist, &sbi->sbi_cchead); -} + CODA_ALLOC(cc, struct coda_cache *, sizeof(*cc)); -/* insert a acl-cache entry in the inode list */ -static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii) -{ - ENTRY; - if ( !cii || !el || ! list_empty(&el->cc_cnlist)) { - printk("coda_cninsert: NULL cii or el->cc_cnlist not empty!\n"); - return ; + if ( !cc ) { + printk("Out of memory in coda_cache_create!\n"); + return NULL; } - list_add(&el->cc_cnlist, &cii->c_cnhead); -} -/* remove a cache entry from the superblock list */ -static void coda_ccremove(struct coda_cache *el) -{ - ENTRY; - if ( ! list_empty(&el->cc_cclist) ) - list_del(&el->cc_cclist); - else - printk("coda_ccremove: loose cc entry!"); -} + coda_load_creds(&cc->cc_cred); + cc->cc_mask = 0; -/* remove a cache entry from the inode's list */ -static void coda_cnremove(struct coda_cache *el) -{ - ENTRY; - if ( ! list_empty(&el->cc_cnlist) ) - list_del(&el->cc_cnlist); - else - printk("coda_cnremove: loose cn entry!"); + INIT_LIST_HEAD(&cc->cc_cclist); + INIT_LIST_HEAD(&cc->cc_cnlist); + list_add(&cc->cc_cclist, &sbi->sbi_cchead); + list_add(&cc->cc_cnlist, &cii->c_cnhead); + + return cc; } -/* create a new cache entry and enlist it */ -static void coda_cache_create(struct inode *inode, int mask) +/* destroy an acl cache entry */ +static void coda_cache_destroy(struct coda_cache *el) { - struct coda_inode_info *cii = 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"); + if (list_empty(&el->cc_cclist) || list_empty(&el->cc_cnlist)) { + printk("coda_cache_destroy: loose entry!"); 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); - coda_ccinsert(cc, sb); + list_del(&el->cc_cclist); + list_del(&el->cc_cnlist); + CODA_FREE(el, sizeof(struct coda_cache)); } /* see if there is a match for the current @@ -107,11 +73,11 @@ static void coda_cache_create(struct inode *inode, int mask) static struct coda_cache * coda_cache_find(struct inode *inode) { struct coda_inode_info *cii = ITOC(inode); - struct list_head *lh, *le; + struct list_head *le; struct coda_cache *cc = NULL; - le = lh = &cii->c_cnhead; - while( (le = le->next ) != lh ) { + list_for_each(le, &cii->c_cnhead) + { /* compare name and creds */ cc = list_entry(le, struct coda_cache, cc_cnlist); if ( !coda_cred_ok(&cc->cc_cred) ) @@ -119,7 +85,7 @@ static struct coda_cache * coda_cache_find(struct inode *inode) CDEBUG(D_CACHE, "HIT for ino %ld\n", inode->i_ino ); return cc; /* cache hit */ } - return NULL; + return NULL; } /* create or extend an acl cache hit */ @@ -129,11 +95,10 @@ void coda_cache_enter(struct inode *inode, int mask) cc = coda_cache_find(inode); - if ( cc ) { + if (!cc) + cc = coda_cache_create(inode); + if (cc) cc->cc_mask |= mask; - } else { - coda_cache_create(inode, mask); - } } /* remove all cached acl matches from an inode */ @@ -154,9 +119,7 @@ void coda_cache_clear_inode(struct inode *inode) while ( le != &cii->c_cnhead ) { cc = list_entry(le, struct coda_cache, cc_cnlist); le = le->next; - coda_cnremove(cc); - coda_ccremove(cc); - CODA_FREE(cc, sizeof(*cc)); + coda_cache_destroy(cc); } } @@ -172,16 +135,11 @@ void coda_cache_clear_all(struct super_block *sb) return; } - if ( list_empty(&sbi->sbi_cchead) ) - return; - le = sbi->sbi_cchead.next; while ( le != &sbi->sbi_cchead ) { cc = list_entry(le, struct coda_cache, cc_cclist); le = le->next; - coda_cnremove(cc); - coda_ccremove(cc); - CODA_FREE(cc, sizeof(*cc)); + coda_cache_destroy(cc); } } @@ -197,18 +155,12 @@ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred) return; } - if (list_empty(&sbi->sbi_cchead)) - return; - le = sbi->sbi_cchead.next; while ( le != &sbi->sbi_cchead ) { cc = list_entry(le, struct coda_cache, cc_cclist); le = le->next; - if ( coda_cred_eq(&cc->cc_cred, cred)) { - coda_cnremove(cc); - coda_ccremove(cc); - CODA_FREE(cc, sizeof(*cc)); - } + if ( coda_cred_eq(&cc->cc_cred, cred)) + coda_cache_destroy(cc); } } @@ -218,11 +170,11 @@ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred) int coda_cache_check(struct inode *inode, int mask) { struct coda_inode_info *cii = ITOC(inode); - struct list_head *lh, *le; + struct list_head *le; struct coda_cache *cc = NULL; - le = lh = &cii->c_cnhead; - while( (le = le->next ) != lh ) { + list_for_each(le, &cii->c_cnhead) + { /* compare name and creds */ cc = list_entry(le, struct coda_cache, cc_cnlist); if ( (cc->cc_mask & mask) != mask ) @@ -232,8 +184,8 @@ int coda_cache_check(struct inode *inode, int mask) 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; + CDEBUG(D_CACHE, "MISS for ino %ld\n", inode->i_ino ); + return 0; } @@ -276,10 +228,9 @@ static void coda_flag_children(struct dentry *parent, int flag) struct list_head *child; struct dentry *de; - child = parent->d_subdirs.next; - while ( child != &parent->d_subdirs ) { + list_for_each(child, &parent->d_subdirs) + { de = list_entry(child, struct dentry, d_child); - child = child->next; /* don't know what to do with negative dentries */ if ( ! de->d_inode ) continue; @@ -307,17 +258,3 @@ void coda_flag_inode_children(struct inode *inode, int flag) dput(alias_de); } -/* this will not zap the inode away */ -void coda_flag_inode(struct inode *inode, int flag) -{ - struct coda_inode_info *cii; - - if ( !inode ) { - 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 47f853c14..7c5544612 100644 --- a/fs/coda/cnode.c +++ b/fs/coda/cnode.c @@ -50,6 +50,7 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr) } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &coda_symlink_inode_operations; inode->i_data.a_ops = &coda_symlink_aops; + inode->i_mapping = &inode->i_data; } else init_special_inode(inode, inode->i_mode, attr->va_rdev); } @@ -65,13 +66,25 @@ struct inode * coda_iget(struct super_block * sb, ViceFid * fid, inode = iget(sb, ino); if ( !inode ) { CDEBUG(D_CNODE, "coda_iget: no inode\n"); - return NULL; + return ERR_PTR(-ENOMEM); } /* check if the inode is already initialized */ cii = ITOC(inode); - if (cii->c_magic == CODA_CNODE_MAGIC) + if (cii->c_magic == CODA_CNODE_MAGIC) { + /* see if it is the right one (might have an inode collision) */ + if ( !coda_fideq(fid, &cii->c_fid) ) { + printk("coda_iget: initialized inode old %s new %s!\n", + coda_f2s(&cii->c_fid), coda_f2s2(fid)); + iput(inode); + return ERR_PTR(-ENOENT); + } + /* replace the attributes, type might have changed */ + coda_fill_inode(inode, attr); goto out; + } + + /* new, empty inode found... initializing */ /* Initialize the Coda inode info structure */ memset(cii, 0, (int) sizeof(struct coda_inode_info)); @@ -90,15 +103,17 @@ struct inode * coda_iget(struct super_block * sb, ViceFid * fid, if ( coda_f2i(fid) == ino ) goto out; - /* check if we expect this weird fid */ - if ( !coda_fid_is_weird(fid) ) + /* check if we expected this weird fid */ + if ( !coda_fid_is_weird(fid) ) { printk("Coda: unknown weird fid: ino %ld, fid %s." "Tell Peter.\n", (long)ino, coda_f2s(&cii->c_fid)); + goto out; + } /* add the inode to a global list so we can find it back later */ list_add(&cii->c_volrootlist, &sbi->sbi_volroothead); CDEBUG(D_CNODE, "Added %ld, %s to volroothead\n", - (long)ino, coda_f2s(&cii->c_fid)); + (long)ino, coda_f2s(&cii->c_fid)); out: return inode; } @@ -111,7 +126,6 @@ out: */ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb) { - struct coda_inode_info *cnp; struct coda_vattr attr; int error; @@ -125,32 +139,22 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb) "coda_cnode_make: coda_getvattr returned %d for %s.\n", error, coda_f2s(fid)); *inode = NULL; + EXIT; return error; } *inode = coda_iget(sb, fid, &attr); - if ( !(*inode) ) { + if ( IS_ERR(*inode) ) { printk("coda_cnode_make: coda_iget failed\n"); - return -ENOMEM; - } - - cnp = ITOC(*inode); - /* see if it is the right one (we might have an inode collision) */ - if ( coda_fideq(fid, &cnp->c_fid) ) { - 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; - } + return PTR_ERR(*inode); + } - /* collision */ - printk("coda_cnode_make on initialized inode %ld, old %s new %s!\n", - (*inode)->i_ino, coda_f2s(&cnp->c_fid), coda_f2s2(fid)); - iput(*inode); + CDEBUG(D_DOWNCALL, "Done making inode: ino %ld, count %d with %s\n", + (*inode)->i_ino, atomic_read(&(*inode)->i_count), + coda_f2s(&(*inode)->u.coda_i.c_fid)); EXIT; - return -ENOENT; + return 0; } @@ -168,7 +172,8 @@ void coda_replace_fid(struct inode *inode, struct ViceFid *oldfid, cnp->c_fid = *newfid; list_del(&cnp->c_volrootlist); - if ( !coda_fid_is_weird(newfid) ) + INIT_LIST_HEAD(&cnp->c_volrootlist); + if ( coda_fid_is_weird(newfid) ) list_add(&cnp->c_volrootlist, &sbi->sbi_volroothead); return; @@ -184,10 +189,9 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb) { ino_t nr; struct inode *inode; - struct coda_inode_info *cnp; + struct coda_inode_info *cii; ENTRY; - if ( !sb ) { printk("coda_fid_to_inode: no sb!\n"); return NULL; @@ -201,7 +205,6 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb) if ( coda_fid_is_weird(fid) ) { - struct coda_inode_info *cii; struct list_head *lh, *le; struct coda_sb_info *sbi = coda_sbp(sb); le = lh = &sbi->sbi_volroothead; @@ -209,19 +212,19 @@ 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); - CDEBUG(D_DOWNCALL, "iterating, now doing %s, ino %ld\n", + /* paranoia check, should never trigger */ + if ( cii->c_magic != CODA_CNODE_MAGIC ) + printk("coda_fid_to_inode: Bad magic in inode %x.\n", cii->c_magic); + + 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", inode->i_ino); - if ( cii->c_magic != CODA_CNODE_MAGIC ) - printk("%s: Bad magic in inode, tell Peter.\n", - __FUNCTION__); - iget(sb, inode->i_ino); return inode; } - } return NULL; } @@ -236,27 +239,27 @@ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb) } /* check if this inode is linked to a cnode */ - cnp = ITOC(inode); - if ( cnp->c_magic != CODA_CNODE_MAGIC ) { + cii = ITOC(inode); + if ( cii->c_magic != CODA_CNODE_MAGIC ) { CDEBUG(D_INODE, "uninitialized inode. Return.\n"); - iput(inode); - return NULL; + goto bad_inode; } - /* 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)) ) { - /* printk("coda_fid2inode: bad cnode (ino %ld, fid %s)" - "Tell Peter.\n", nr, coda_f2s(fid)); */ - iput(inode); - return NULL; + /* make sure fid is the one we want */ + if ( !coda_fideq(fid, &(cii->c_fid)) ) { +#if 0 + printk("coda_fid2inode: bad cnode (ino %ld, fid %s)", nr, + coda_f2s(fid)); +#endif + goto bad_inode; } CDEBUG(D_INODE, "found %ld\n", inode->i_ino); return inode; + +bad_inode: + iput(inode); + return NULL; } /* the CONTROL inode is made without asking attributes from Venus */ @@ -276,3 +279,4 @@ int coda_cnode_makectl(struct inode **inode, struct super_block *sb) return error; } + diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 83f7bbcc5..0faf29663 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -48,11 +48,15 @@ static int coda_dentry_revalidate(struct dentry *de, int); static int coda_dentry_delete(struct dentry *); /* support routines */ +static void coda_prepare_fakefile(struct inode *coda_inode, + struct file *coda_file, + struct inode *open_inode, + struct file *open_file, + struct dentry *open_dentry); static int coda_venus_readdir(struct file *filp, void *dirent, filldir_t filldir); -int coda_fsync(struct file *, struct dentry *dentry); +int coda_fsync(struct file *, struct dentry *dentry, int); -int coda_crossvol_rename = 0; int coda_hasmknod = 0; struct dentry_operations coda_dentry_operations = @@ -90,38 +94,36 @@ struct file_operations coda_dir_operations = { /* acces routines: lookup, readlink, permission */ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry) { - struct coda_inode_info *dircnp; struct inode *res_inode = NULL; - struct ViceFid resfid; + struct ViceFid resfid = {0,0,0}; int dropme = 0; /* to indicate entry should not be cached */ - int type; + int type = 0; int error = 0; const char *name = entry->d_name.name; size_t length = entry->d_name.len; ENTRY; - dircnp = ITOC(dir); - if ( length > CODA_MAXNAMLEN ) { printk("name too long: lookup, %s (%*s)\n", - coda_f2s(&dircnp->c_fid), (int)length, name); + coda_i2s(dir), (int)length, name); return ERR_PTR(-ENAMETOOLONG); } CDEBUG(D_INODE, "name %s, len %ld in ino %ld, fid %s\n", - name, (long)length, dir->i_ino, coda_f2s(&dircnp->c_fid)); + name, (long)length, dir->i_ino, coda_i2s(dir)); /* control object, create inode on the fly */ if (coda_isroot(dir) && coda_iscontrol(name, length)) { error = coda_cnode_makectl(&res_inode, dir->i_sb); CDEBUG(D_SPECIAL, "Lookup on CTL object; dir ino %ld, count %d\n", - dir->i_ino, dir->i_count); + dir->i_ino, atomic_read(&dir->i_count)); + dropme = 1; goto exit; } - error = venus_lookup(dir->i_sb, &(dircnp->c_fid), + error = venus_lookup(dir->i_sb, coda_i2f(dir), (const char *)name, length, &type, &resfid); res_inode = NULL; @@ -132,12 +134,17 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry) coda_f2s(&resfid)); dropme = 1; } + error = coda_cnode_make(&res_inode, &resfid, dir->i_sb); - if (error) - return ERR_PTR(error); + if (error) return ERR_PTR(error); + + /* make sure we drop unexpected weird fid's */ + if (coda_f2i(&resfid) != res_inode->i_ino && + !coda_fid_is_weird(&resfid)) + dropme = 1; } else if (error != -ENOENT) { CDEBUG(D_INODE, "error for %s(%*s)%d\n", - coda_f2s(&dircnp->c_fid), (int)length, name, error); + coda_i2s(dir), (int)length, name, error); return ERR_PTR(error); } CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n", @@ -149,7 +156,7 @@ exit: d_add(entry, res_inode); if ( dropme ) { d_drop(entry); - ITOC(res_inode)->c_flags |= C_VATTR; + coda_flag_inode(res_inode, C_VATTR); } EXIT; return NULL; @@ -158,16 +165,14 @@ exit: int coda_permission(struct inode *inode, int mask) { - struct coda_inode_info *cp = ITOC(inode); int error; ENTRY; coda_vfs_stat.permission++; coda_permission_stat.count++; - if ( mask == 0 ) { + if ( mask == 0 ) return 0; - } if ( coda_access_cache == 1 ) { if ( coda_cache_check(inode, mask) ) { @@ -176,28 +181,39 @@ int coda_permission(struct inode *inode, int mask) } } - cp = ITOC(inode); - CDEBUG(D_INODE, "mask is %o\n", mask); - error = venus_access(inode->i_sb, &(cp->c_fid), mask); + error = venus_access(inode->i_sb, coda_i2f(inode), mask); CDEBUG(D_INODE, "fid: %s, ino: %ld (mask: %o) error: %d\n", - coda_f2s(&(cp->c_fid)), inode->i_ino, mask, error); + coda_i2s(inode), inode->i_ino, mask, error); - if ( error == 0 ) { + if (!error) coda_cache_enter(inode, mask); - } return error; } -/* creation routines: create, mknod, mkdir, link, symlink */ +static inline void coda_dir_changed(struct inode *dir, int link) +{ +#ifdef REQUERY_VENUS_FOR_MTIME + /* invalidate the directory cnode's attributes so we refetch the + * attributes from venus next time the inode is referenced */ + coda_flag_inode(dir, C_VATTR); +#else + /* optimistically we can also act as if our nose bleeds. The + * granularity of the mtime is coarse anyways so we might actually be + * right most of the time. Note: we only do this for directories. */ + dir->i_mtime = CURRENT_TIME; +#endif + if (link) + dir->i_nlink += link; +} +/* creation routines: create, mknod, mkdir, link, symlink */ static int coda_create(struct inode *dir, struct dentry *de, int mode) { 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; @@ -207,14 +223,12 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode) ENTRY; coda_vfs_stat.create++; - CDEBUG(D_INODE, "name: %s, length %d, mode %o\n",name, length, mode); + CDEBUG(D_INODE, "name: %s, length %d, mode %o\n", name, length, mode); if (coda_isroot(dir) && coda_iscontrol(name, length)) return -EPERM; - dircnp = ITOC(dir); - - error = venus_create(dir->i_sb, &(dircnp->c_fid), name, length, + error = venus_create(dir->i_sb, coda_i2f(dir), name, length, 0, mode, 0, &newfid, &attrs); if ( error ) { @@ -232,15 +246,14 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode) } /* invalidate the directory cnode's attributes */ - dircnp->c_flags |= C_VATTR; + coda_dir_changed(dir, 0); 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; @@ -258,9 +271,7 @@ static int coda_mknod(struct inode *dir, struct dentry *de, int mode, int rdev) if (coda_isroot(dir) && coda_iscontrol(name, length)) return -EPERM; - dircnp = ITOC(dir); - - error = venus_create(dir->i_sb, &(dircnp->c_fid), name, length, + error = venus_create(dir->i_sb, coda_i2f(dir), name, length, 0, mode, rdev, &newfid, &attrs); if ( error ) { @@ -278,14 +289,13 @@ static int coda_mknod(struct inode *dir, struct dentry *de, int mode, int rdev) } /* invalidate the directory cnode's attributes */ - dircnp->c_flags |= C_VATTR; + coda_dir_changed(dir, 0); d_instantiate(de, result); return 0; } static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) { - struct coda_inode_info *dircnp; struct inode *inode; struct coda_vattr attr; const char *name = de->d_name.name; @@ -299,13 +309,11 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) if (coda_isroot(dir) && coda_iscontrol(name, len)) return -EPERM; - dircnp = ITOC(dir); - CDEBUG(D_INODE, "mkdir %s (len %d) in %s, mode %o.\n", - name, len, coda_f2s(&(dircnp->c_fid)), mode); + name, len, coda_i2s(dir), mode); attr.va_mode = mode; - error = venus_mkdir(dir->i_sb, &(dircnp->c_fid), + error = venus_mkdir(dir->i_sb, coda_i2f(dir), name, len, &newfid, &attr); if ( error ) { @@ -325,8 +333,7 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) } /* invalidate the directory cnode's attributes */ - dircnp->c_flags |= C_VATTR; - dir->i_nlink++; + coda_dir_changed(dir, 1); d_instantiate(de, inode); return 0; } @@ -338,7 +345,6 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode, struct inode *inode = source_de->d_inode; const char * name = de->d_name.name; int len = de->d_name.len; - struct coda_inode_info *dir_cnp, *cnp; int error; ENTRY; @@ -347,28 +353,26 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode, if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) return -EPERM; - dir_cnp = ITOC(dir_inode); - cnp = ITOC(inode); - - CDEBUG(D_INODE, "old: fid: %s\n", coda_f2s(&(cnp->c_fid))); - CDEBUG(D_INODE, "directory: %s\n", coda_f2s(&(dir_cnp->c_fid))); + CDEBUG(D_INODE, "old: fid: %s\n", coda_i2s(inode)); + CDEBUG(D_INODE, "directory: %s\n", coda_i2s(dir_inode)); - error = venus_link(dir_inode->i_sb,&(cnp->c_fid), &(dir_cnp->c_fid), - (const char *)name, len); + error = venus_link(dir_inode->i_sb, coda_i2f(inode), + coda_i2f(dir_inode), (const char *)name, len); - if ( ! error ) { - dir_cnp->c_flags |= C_VATTR; - ++inode->i_count; - d_instantiate(de, inode); - inode->i_nlink++; - } else { + if (error) { d_drop(de); - return error; + goto out; } - CDEBUG(D_INODE, "link result %d\n",error); + coda_dir_changed(dir_inode, 0); + atomic_inc(&inode->i_count); + d_instantiate(de, inode); + inode->i_nlink++; + +out: + CDEBUG(D_INODE, "link result %d\n",error); EXIT; - return(error); + return(error); } @@ -377,7 +381,6 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de, { const char *name = de->d_name.name; int len = de->d_name.len; - struct coda_inode_info *dir_cnp = ITOC(dir_inode); int symlen; int error=0; @@ -398,13 +401,12 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de, * 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, + error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len, symname, symlen); /* mtime is no good anymore */ - if ( !error ) { - dir_cnp->c_flags |= C_VATTR; - } + if ( !error ) + coda_dir_changed(dir_inode, 0); CDEBUG(D_INODE, "in symlink result %d\n",error); EXIT; @@ -414,7 +416,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 = ITOC(dir); int error; const char *name = de->d_name.name; int len = de->d_name.len; @@ -423,16 +424,15 @@ int coda_unlink(struct inode *dir, struct dentry *de) coda_vfs_stat.unlink++; CDEBUG(D_INODE, " %s in %s, dirino %ld\n", name , - coda_f2s(&(dircnp->c_fid)), dir->i_ino); + coda_i2s(dir), dir->i_ino); - error = venus_remove(dir->i_sb, &(dircnp->c_fid), name, len); + error = venus_remove(dir->i_sb, coda_i2f(dir), name, len); if ( error ) { CDEBUG(D_INODE, "upc returned error %d\n", error); return error; } - /* cache management: mtime has changed, ask Venus */ - dircnp->c_flags |= C_VATTR; + coda_dir_changed(dir, 0); de->d_inode->i_nlink--; return 0; @@ -440,7 +440,6 @@ int coda_unlink(struct inode *dir, struct dentry *de) int coda_rmdir(struct inode *dir, struct dentry *de) { - struct coda_inode_info *dircnp; const char *name = de->d_name.name; int len = de->d_name.len; int error; @@ -448,19 +447,18 @@ int coda_rmdir(struct inode *dir, struct dentry *de) ENTRY; coda_vfs_stat.rmdir++; - dircnp = ITOC(dir); - if (!d_unhashed(de)) return -EBUSY; - error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len); + error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len); if ( error ) { CDEBUG(D_INODE, "upc returned error %d\n", error); return error; } - if (de->d_inode->i_nlink) - de->d_inode->i_nlink --; + coda_dir_changed(dir, -1); + de->d_inode->i_nlink--; + d_delete(de); return 0; } @@ -473,43 +471,38 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, const char *new_name = new_dentry->d_name.name; int old_length = old_dentry->d_name.len; int new_length = new_dentry->d_name.len; - struct inode *new_inode = new_dentry->d_inode; - struct coda_inode_info *new_cnp, *old_cnp; int error; ENTRY; coda_vfs_stat.rename++; - old_cnp = ITOC(old_dir); - new_cnp = ITOC(new_dir); - - CDEBUG(D_INODE, "old: %s, (%d length, %ld strlen), new: %s" - "(%d length, %ld strlen).old:d_count: %d, new:d_count: %d\n", - old_name, old_length, (long)strlen(old_name), new_name, new_length, - (long)strlen(new_name),old_dentry->d_count, new_dentry->d_count); - - /* 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; + CDEBUG(D_INODE, "old: %s, (%d length), new: %s" + "(%d length). old:d_count: %d, new:d_count: %d\n", + old_name, old_length, new_name, new_length, + old_dentry->d_count, new_dentry->d_count); - error = venus_rename(old_dir->i_sb, &(old_cnp->c_fid), - &(new_cnp->c_fid), old_length, new_length, + error = venus_rename(old_dir->i_sb, coda_i2f(old_dir), + coda_i2f(new_dir), old_length, new_length, (const char *) old_name, (const char *)new_name); - if ( error ) { - CDEBUG(D_INODE, "returned error %d\n", error); - return error; - } + if ( !error ) { + if ( new_dentry->d_inode ) { + if ( S_ISDIR(new_dentry->d_inode->i_mode) ) { + old_dir->i_nlink--; + new_dir->i_nlink++; + } + coda_flag_inode(new_dentry->d_inode, C_VATTR); + } - coda_flag_inode(new_inode, C_VATTR); - coda_flag_inode(old_dir, C_VATTR); - coda_flag_inode(new_dir, C_VATTR); + /* coda_flag_inode(old_dir, C_VATTR); */ + /* coda_flag_inode(new_dir, C_VATTR); */ + old_dir->i_mtime = new_dir->i_mtime = CURRENT_TIME; + } CDEBUG(D_INODE, "result %d\n", error); EXIT; - return 0; + return error; } @@ -517,43 +510,70 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, int coda_readdir(struct file *file, void *dirent, filldir_t filldir) { int result = 0; - struct coda_inode_info *cnp; struct file open_file; struct dentry open_dentry; - struct inode *inode=file->f_dentry->d_inode; + struct inode *inode=file->f_dentry->d_inode, *container; ENTRY; coda_vfs_stat.readdir++; - cnp = ITOC(inode); - if ( !cnp->c_ovp ) { - CDEBUG(D_FILE, "open inode pointer = NULL.\n"); + if ( inode->i_mapping == &inode->i_data ) { + CDEBUG(D_FILE, "no container inode.\n"); return -EIO; } - coda_prepare_openfile(inode, file, cnp->c_ovp, &open_file, - &open_dentry); - if ( S_ISREG(cnp->c_ovp->i_mode) ) { + container = (struct inode *)inode->i_mapping->host; + + coda_prepare_fakefile(inode, file, container, &open_file, &open_dentry); + + if ( S_ISREG(container->i_mode) ) { /* Venus: we must read Venus dirents from the file */ result = coda_venus_readdir(&open_file, dirent, filldir); } else { - /* potemkin case: we are handed a directory inode */ + /* potemkin case: we are handed a directory inode */ result = vfs_readdir(&open_file, filldir, dirent); } - coda_restore_codafile(inode, file, cnp->c_ovp, &open_file); + + /* we only have to restore the file position (and f_version?) */ + file->f_pos = open_file.f_pos; + file->f_version = open_file.f_version; + EXIT; return result; } +/* grab the ext2 inode of the container file */ +static int coda_inode_grab(dev_t dev, ino_t ino, struct inode **ind) +{ + struct super_block *sbptr; + + sbptr = get_super(dev); + + if ( !sbptr ) { + printk("coda_inode_grab: coda_find_super returns NULL.\n"); + return -ENXIO; + } + + *ind = NULL; + *ind = iget(sbptr, ino); + + if ( *ind == NULL ) { + printk("coda_inode_grab: iget(dev: %d, ino: %ld) " + "returns NULL.\n", dev, (long)ino); + return -ENOENT; + } + CDEBUG(D_FILE, "ino: %ld, ops at %p\n", (long)ino, (*ind)->i_op); + return 0; +} + /* ask venus to cache the file and return the inode of the container file, put this inode pointer in the cnode for future read/writes */ int coda_open(struct inode *i, struct file *f) { ino_t ino; dev_t dev; - struct coda_inode_info *cnp; int error = 0; - struct inode *cont_inode = NULL; + struct inode *cont_inode = NULL, *old_container; unsigned short flags = f->f_flags & (~O_EXCL); unsigned short coda_flags = coda_flags_to_cflags(flags); struct coda_cred *cred; @@ -564,10 +584,7 @@ int coda_open(struct inode *i, struct file *f) 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); - - - error = venus_open(i->i_sb, &(cnp->c_fid), coda_flags, &ino, &dev); + error = venus_open(i->i_sb, coda_i2f(i), coda_flags, &ino, &dev); if (error) { CDEBUG(D_FILE, "venus: dev %d, inode %ld, out->result %d\n", dev, (long)ino, error); @@ -589,25 +606,25 @@ int coda_open(struct inode *i, struct file *f) coda_load_creds(cred); f->private_data = cred; - if ( cnp->c_ovp ) - iput(cnp->c_ovp); - - cnp->c_ovp = cont_inode; + if ( i->i_mapping != &i->i_data ) { + old_container = (struct inode *)i->i_mapping->host; + i->i_mapping = &i->i_data; + iput(old_container); + } i->i_mapping = cont_inode->i_mapping; - cnp->c_ocount++; - 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 %p\n", - cnp->c_ovp->i_ino, cnp->c_ovp->i_count, - (cnp->c_ovp->i_op)); + CDEBUG(D_FILE, "result %d, coda i->i_count is %d for ino %ld\n", + error, atomic_read(&i->i_count), i->i_ino); + CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %p\n", + cont_inode->i_ino, atomic_read(&cont_inode->i_count), + cont_inode->i_op); EXIT; return 0; } int coda_release(struct inode *i, struct file *f) { - struct coda_inode_info *cnp; + struct inode *container = NULL; int error = 0; unsigned short flags = (f->f_flags) & (~O_EXCL); unsigned short cflags = coda_flags_to_cflags(flags); @@ -618,29 +635,15 @@ int coda_release(struct inode *i, struct file *f) cred = (struct coda_cred *)f->private_data; - cnp =ITOC(i); - CHECK_CNODE(cnp); - CDEBUG(D_FILE, - "RELEASE coda (ino %ld, ct %d) cache (ino %ld, ct %d)\n", - i->i_ino, i->i_count, (cnp->c_ovp ? cnp->c_ovp->i_ino : 0), - (cnp->c_ovp ? cnp->c_ovp->i_count : -99)); + if (i->i_mapping != &i->i_data) + container = (struct inode *)i->i_mapping->host; + CDEBUG(D_FILE, "RELEASE coda (ino %ld, ct %d) cache (ino %ld, ct %d)\n", + i->i_ino, atomic_read(&i->i_count), + (container ? container->i_ino : 0), + (container ? atomic_read(&container->i_count) : -99)); - /* even when c_ocount=0 we cannot put c_ovp to - * NULL since the file may be mmapped. - * See code in inode.c (coda_put_inode) for - * further handling of close. - */ - - --cnp->c_ocount; - - if ( flags & (O_WRONLY | O_RDWR) ) - --cnp->c_owrite; - - /* Venus closing a container file? don't bother making the upcall. */ - if ( current->pid != coda_upc_comm.vc_pid ) { - error = venus_release(i->i_sb, &(cnp->c_fid), cflags, cred); - } + error = venus_release(i->i_sb, coda_i2f(i), cflags, cred); f->private_data = NULL; if (cred) @@ -651,13 +654,29 @@ int coda_release(struct inode *i, struct file *f) } /* support routines */ + +/* instantiate a fake file and dentry to pass to coda_venus_readdir */ +static void coda_prepare_fakefile(struct inode *i, struct file *coda_file, + struct inode *cont_inode, + struct file *cont_file, + struct dentry *cont_dentry) +{ + cont_file->f_dentry = cont_dentry; + cont_file->f_dentry->d_inode = cont_inode; + cont_file->f_pos = coda_file->f_pos; + cont_file->f_version = coda_file->f_version; + cont_file->f_op = cont_inode->i_fop; + return ; +} + /* * this structure is manipulated by filldir in vfs layer. * the count holds the remaining amount of space in the getdents buffer, * beyond the current_dir pointer. + * + * What structure is this comment referring to?? -JH */ - /* should be big enough to hold any single directory entry */ #define DIR_BUFSIZE 2048 @@ -767,13 +786,12 @@ static int coda_dentry_revalidate(struct dentry *de, int flags) if (!inode) return 1; - - cii = ITOC(de->d_inode); if (coda_isroot(inode)) return 1; if (is_bad_inode(inode)) return 0; + cii = ITOC(de->d_inode); if (! (cii->c_flags & (C_PURGE | C_FLUSH)) ) return valid; @@ -807,7 +825,7 @@ static int coda_dentry_delete(struct dentry * dentry) if (!dentry->d_inode) return 0; - flags = (ITOC(dentry->d_inode)->c_flags) & C_PURGE; + 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, @@ -825,14 +843,13 @@ static int coda_dentry_delete(struct dentry * dentry) * cache manager Venus issues a downcall to the kernel when this * happens */ - int coda_revalidate_inode(struct dentry *dentry) { struct coda_vattr attr; int error = 0; int old_mode; ino_t old_ino; - struct inode *inode = dentry->d_inode; + struct inode *inode = dentry->d_inode, *container; struct coda_inode_info *cii = ITOC(inode); ENTRY; @@ -843,14 +860,6 @@ int coda_revalidate_inode(struct dentry *dentry) if ( cii->c_flags == 0 ) return 0; - /* Venus accessing a container file, don't try to revalidate */ - if ( current->pid == coda_upc_comm.vc_pid ) - return 0; - - /* Venus closed the device .... */ - if ( cii->c_flags & C_DYING ) - goto return_bad_inode; - if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) { error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr); if ( error ) @@ -865,7 +874,6 @@ int coda_revalidate_inode(struct dentry *dentry) old_ino = inode->i_ino; coda_vattr_to_iattr(inode, &attr); - if ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT)) { printk("Coda: inode %ld, fid %s changed type!\n", inode->i_ino, coda_f2s(&(cii->c_fid))); @@ -885,10 +893,10 @@ int coda_revalidate_inode(struct dentry *dentry) return 0; return_bad_inode: - if ( cii->c_ovp ) { - iput(cii->c_ovp); + if ( inode->i_mapping != &inode->i_data ) { + container = (struct inode *)inode->i_mapping->host; inode->i_mapping = &inode->i_data; - cii->c_ovp = NULL; + iput(container); } make_bad_inode(inode); return -EIO; diff --git a/fs/coda/file.c b/fs/coda/file.c index ab805cf11..704b4d00b 100644 --- a/fs/coda/file.c +++ b/fs/coda/file.c @@ -26,139 +26,58 @@ #include <linux/coda_cache.h> #include <linux/coda_proc.h> -/* file operations */ -static int coda_file_mmap(struct file * file, struct vm_area_struct * vma); - -/* also exported from this file (used for dirs) */ -int coda_fsync(struct file *, struct dentry *dentry); - -struct inode_operations coda_file_inode_operations = { - permission: coda_permission, - revalidate: coda_revalidate_inode, - setattr: coda_notify_change, -}; - -struct file_operations coda_file_operations = { - read: generic_file_read, - write: generic_file_write, - mmap: coda_file_mmap, - open: coda_open, - release: coda_release, - fsync: coda_fsync, -}; - -/* File operations */ - -static int coda_file_mmap(struct file * file, struct vm_area_struct * vma) +static ssize_t +coda_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos) { - struct coda_inode_info *cii; - int res; + struct inode *inode = file->f_dentry->d_inode; + ssize_t n; - coda_vfs_stat.file_mmap++; + n = generic_file_write(file, buf, count, ppos); - ENTRY; - cii = ITOC(file->f_dentry->d_inode); - cii->c_mmcount++; - - res =generic_file_mmap(file, vma); - EXIT; - return res; + inode->i_size = ((struct inode*)inode->i_mapping->host)->i_size; + + return n; } -int coda_fsync(struct file *coda_file, struct dentry *coda_dentry) +/* exported from this file (used for dirs) */ +int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync) { - struct coda_inode_info *cnp; - struct inode *coda_inode = coda_dentry->d_inode; - struct inode *cont_inode = NULL; - struct file cont_file; + struct inode *inode = coda_dentry->d_inode; struct dentry cont_dentry; - int result = 0; - ENTRY; + int result = 0; + ENTRY; coda_vfs_stat.fsync++; - if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) || - S_ISLNK(coda_inode->i_mode))) + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) return -EINVAL; - lock_kernel(); - 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"); - unlock_kernel(); + if ( inode->i_mapping == &inode->i_data ) { + printk("coda_fsync: no container inode!\n"); return -1; } - coda_prepare_openfile(coda_inode, coda_file, cont_inode, - &cont_file, &cont_dentry); - - down(&cont_inode->i_sem); + cont_dentry.d_inode = (struct inode *)inode->i_mapping->host; + + down(&cont_dentry.d_inode->i_sem); + result = file_fsync(NULL, &cont_dentry, datasync); + up(&cont_dentry.d_inode->i_sem); - result = file_fsync(&cont_file ,&cont_dentry); - if ( result == 0 ) { - result = venus_fsync(coda_inode->i_sb, &(cnp->c_fid)); + if ( !datasync && result == 0 ) { + lock_kernel(); + result = venus_fsync(inode->i_sb, coda_i2f(inode)); + unlock_kernel(); } - up(&cont_inode->i_sem); - - coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file); - unlock_kernel(); - return result; + return result; } -/* - * support routines - */ -/* instantiate the container file and dentry object to do io */ -void coda_prepare_openfile(struct inode *i, struct file *coda_file, - struct inode *cont_inode, struct file *cont_file, - struct dentry *cont_dentry) -{ - cont_file->f_pos = coda_file->f_pos; - cont_file->f_mode = coda_file->f_mode; - cont_file->f_flags = coda_file->f_flags; - atomic_set(&cont_file->f_count, atomic_read(&coda_file->f_count)); - cont_file->f_owner = coda_file->f_owner; - cont_file->f_op = cont_inode->i_fop; - cont_file->f_dentry = cont_dentry; - cont_file->f_dentry->d_inode = cont_inode; - return ; -} - -/* update the Coda file & inode after I/O */ -void coda_restore_codafile(struct inode *coda_inode, struct file *coda_file, - struct inode *open_inode, struct file *open_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_size = open_inode->i_size; - return; -} - -/* grab the ext2 inode of the container file */ -int coda_inode_grab(dev_t dev, ino_t ino, struct inode **ind) -{ - struct super_block *sbptr; - - sbptr = get_super(dev); - - if ( !sbptr ) { - printk("coda_inode_grab: coda_find_super returns NULL.\n"); - return -ENXIO; - } - - *ind = NULL; - *ind = iget(sbptr, ino); - - if ( *ind == NULL ) { - printk("coda_inode_grab: iget(dev: %d, ino: %ld) " - "returns NULL.\n", dev, (long)ino); - return -ENOENT; - } - CDEBUG(D_FILE, "ino: %ld, ops at %p\n", (long)ino, (*ind)->i_op); - return 0; -} +struct file_operations coda_file_operations = { + read: generic_file_read, + write: coda_file_write, + mmap: generic_file_mmap, + open: coda_open, + release: coda_release, + fsync: coda_fsync, +}; diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 7f163acf9..84191c494 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -1,7 +1,7 @@ /* * Super block/filesystem wide operations * - * Copryright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and + * Copyright (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> @@ -17,6 +17,7 @@ #include <linux/errno.h> #include <linux/locks.h> #include <linux/unistd.h> +#include <linux/smp_lock.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -34,8 +35,7 @@ /* VFS super_block ops */ static struct super_block *coda_read_super(struct super_block *, void *, int); static void coda_read_inode(struct inode *); -static void coda_put_inode(struct inode *); -static void coda_delete_inode(struct inode *); +static void coda_clear_inode(struct inode *); static void coda_put_super(struct super_block *); static int coda_statfs(struct super_block *sb, struct statfs *buf); @@ -43,8 +43,7 @@ static int coda_statfs(struct super_block *sb, struct statfs *buf); struct super_operations coda_super_operations = { read_inode: coda_read_inode, - put_inode: coda_put_inode, - delete_inode: coda_delete_inode, + clear_inode: coda_clear_inode, put_super: coda_put_super, statfs: coda_statfs, }; @@ -144,83 +143,74 @@ static void coda_read_inode(struct inode *inode) return; } -static void coda_put_inode(struct inode *inode) +static void coda_clear_inode(struct inode *inode) { - ENTRY; - - CDEBUG(D_INODE,"ino: %ld, count %d\n", inode->i_ino, inode->i_count); - - if ( inode->i_count == 1 ) { - write_inode_now(inode); - inode->i_nlink = 0; - } -} - -static void coda_delete_inode(struct inode *inode) -{ - struct coda_inode_info *cii; + struct coda_inode_info *cii = ITOC(inode); struct inode *open_inode; ENTRY; CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n", - inode->i_ino, inode->i_count); + inode->i_ino, atomic_read(&inode->i_count)); - cii = ITOC(inode); - if ( inode->i_ino == CTL_INO || cii->c_magic != CODA_CNODE_MAGIC ) { - clear_inode(inode); - return; - } + if ( inode->i_ino == CTL_INO || cii->c_magic != CODA_CNODE_MAGIC ) + goto out; + + lock_kernel(); - if ( ! list_empty(&cii->c_volrootlist) ) { + if ( !list_empty(&cii->c_volrootlist) ) { list_del(&cii->c_volrootlist); INIT_LIST_HEAD(&cii->c_volrootlist); } - open_inode = cii->c_ovp; - if ( open_inode ) { + if ( inode->i_mapping != &inode->i_data ) { + open_inode = (struct inode *)inode->i_mapping->host; CDEBUG(D_SUPER, "DELINO cached file: ino %ld count %d.\n", - open_inode->i_ino, open_inode->i_count); - cii->c_ovp = NULL; + open_inode->i_ino, atomic_read(&open_inode->i_count)); inode->i_mapping = &inode->i_data; - iput(open_inode); + iput(open_inode); } coda_cache_clear_inode(inode); + unlock_kernel(); + CDEBUG(D_DOWNCALL, "clearing inode: %ld, %x\n", inode->i_ino, cii->c_flags); +out: inode->u.coda_i.c_magic = 0; - clear_inode(inode); EXIT; } int coda_notify_change(struct dentry *de, struct iattr *iattr) { struct inode *inode = de->d_inode; - struct coda_inode_info *cii; struct coda_vattr vattr; int error; ENTRY; memset(&vattr, 0, sizeof(vattr)); - 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, &cii->c_fid, &vattr); + /* Venus is responsible for truncating the container-file!!! */ + error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr); - if ( !error ) { + if ( !error ) { coda_vattr_to_iattr(inode, &vattr); coda_cache_clear_inode(inode); - } - CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n", - inode->i_mode, error); + } + CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n", inode->i_mode, error); EXIT; - return error; + return error; } +struct inode_operations coda_file_inode_operations = { + permission: coda_permission, + revalidate: coda_revalidate_inode, + setattr: coda_notify_change, +}; + static int coda_statfs(struct super_block *sb, struct statfs *buf) { int error; @@ -244,7 +234,6 @@ static int coda_statfs(struct super_block *sb, struct statfs *buf) return 0; } - /* init_coda: used by filesystems.c to register coda */ DECLARE_FSTYPE( coda_fs_type, "coda", coda_read_super, 0); @@ -254,5 +243,3 @@ int init_coda_fs(void) return register_filesystem(&coda_fs_type); } - - diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c index d29c18ccd..d97204125 100644 --- a/fs/coda/pioctl.c +++ b/fs/coda/pioctl.c @@ -120,7 +120,7 @@ static int coda_pioctl(struct inode * inode, struct file * filp, 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, nd.dentry->d_count); + atomic_read(&target_inode->i_count), nd.dentry->d_count); path_release(&nd); return error; } diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index b88c602c6..582ea7000 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -71,7 +71,7 @@ static unsigned int coda_psdev_poll(struct file *file, poll_table * wait) struct venus_comm *vcp = &coda_upc_comm; unsigned int mask = POLLOUT | POLLWRNORM; - poll_wait(file, &(vcp->vc_waitq), wait); + poll_wait(file, &vcp->vc_waitq, wait); if (!list_empty(&vcp->vc_pending)) mask |= POLLIN | POLLRDNORM; @@ -99,24 +99,24 @@ static int coda_psdev_ioctl(struct inode * inode, struct file * filp, */ static ssize_t coda_psdev_write(struct file *file, const char *buf, - size_t count, loff_t *off) + size_t nbytes, loff_t *off) { struct venus_comm *vcp = &coda_upc_comm; struct upc_req *req = NULL; struct upc_req *tmp; struct list_head *lh; struct coda_in_hdr hdr; + ssize_t retval = 0, count = 0; int error; - if ( !coda_upc_comm.vc_pid ) return -EIO; /* Peek at the opcode, uniquefier */ if (copy_from_user(&hdr, buf, 2 * sizeof(u_long))) return -EFAULT; - CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld), count %ld\n", - current->pid, hdr.opcode, hdr.unique, (long)count); + CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%ld,%ld), nbytes %ld\n", + current->pid, hdr.opcode, hdr.unique, (long)nbytes); if (DOWNCALL(hdr.opcode)) { struct super_block *sb = NULL; @@ -125,41 +125,47 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf, sb = coda_super_info.sbi_sb; if ( !sb ) { - printk("coda_psdev_write: downcall, no SB!\n"); - return count; + CDEBUG(D_PSDEV, "coda_psdev_write: downcall, no SB!\n"); + count = nbytes; + goto out; } CDEBUG(D_PSDEV, "handling downcall\n"); - if ( count < sizeof(struct coda_out_hdr) ) { + if ( nbytes < sizeof(struct coda_out_hdr) ) { printk("coda_downcall opc %ld uniq %ld, not enough!\n", hdr.opcode, hdr.unique); - return count; + count = nbytes; + goto out; } - CODA_ALLOC(dcbuf, union outputArgs *, size); - if ( count > size ) { + if ( nbytes > size ) { printk("Coda: downcall opc %ld, uniq %ld, too much!", hdr.opcode, hdr.unique); - count = size; + nbytes = size; + } + CODA_ALLOC(dcbuf, union outputArgs *, nbytes); + if (copy_from_user(dcbuf, buf, nbytes)) { + CODA_FREE(dcbuf, nbytes); + retval = -EFAULT; + goto out; } - if (copy_from_user(dcbuf, buf, count)) - return -EFAULT; /* what downcall errors does Venus handle ? */ lock_kernel(); error = coda_downcall(hdr.opcode, dcbuf, sb); unlock_kernel(); - if ( error) { - printk("psdev_write: coda_downcall error: %d\n", - error); - return 0; + CODA_FREE(dcbuf, nbytes); + if (error) { + printk("psdev_write: coda_downcall error: %d\n", error); + retval = error; + goto out; } - CODA_FREE(dcbuf, size); - return count; + count = nbytes; + goto out; } - /* Look for the message on the processing queue. */ + lock_kernel(); lh = &vcp->vc_processing; while ( (lh = lh->next) != &vcp->vc_processing ) { tmp = list_entry(lh, struct upc_req , uc_chain); @@ -171,31 +177,40 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf, break; } } + unlock_kernel(); + if (!req) { printk("psdev_write: msg (%ld, %ld) not found\n", hdr.opcode, hdr.unique); - return(-ESRCH); + retval = -ESRCH; + goto out; } /* move data into response buffer. */ - if (req->uc_outSize < count) { + if (req->uc_outSize < nbytes) { printk("psdev_write: too much cnt: %d, cnt: %ld, opc: %ld, uniq: %ld.\n", - req->uc_outSize, (long)count, hdr.opcode, hdr.unique); - count = req->uc_outSize; /* don't have more space! */ + req->uc_outSize, (long)nbytes, hdr.opcode, hdr.unique); + nbytes = req->uc_outSize; /* don't have more space! */ + } + if (copy_from_user(req->uc_data, buf, nbytes)) { + req->uc_flags |= REQ_ABORT; + wake_up(&req->uc_sleep); + retval = -EFAULT; + goto out; } - if (copy_from_user(req->uc_data, buf, count)) - return -EFAULT; /* adjust outsize. is this usefull ?? */ - req->uc_outSize = count; + req->uc_outSize = nbytes; req->uc_flags |= REQ_WRITE; + count = nbytes; CDEBUG(D_PSDEV, "Found! Count %ld for (opc,uniq)=(%ld,%ld), upc_req at %p\n", (long)count, hdr.opcode, hdr.unique, &req); wake_up(&req->uc_sleep); - return(count); +out: + return(count ? count : retval); } /* @@ -203,45 +218,71 @@ 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 nbytes, loff_t *off) { + DECLARE_WAITQUEUE(wait, current); struct venus_comm *vcp = &coda_upc_comm; struct upc_req *req; - int result = count ; + ssize_t retval = 0, count = 0; - CDEBUG(D_PSDEV, "count %ld\n", (long)count); - if (list_empty(&(vcp->vc_pending))) { - return -1; - } - - req = list_entry((vcp->vc_pending.next), struct upc_req, uc_chain); - list_del(&(req->uc_chain)); + if (nbytes == 0) + return 0; - /* Move the input args into userspace */ - if (req->uc_inSize <= count) - result = req->uc_inSize; + lock_kernel(); - if (count < req->uc_inSize) { + add_wait_queue(&vcp->vc_waitq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (list_empty(&vcp->vc_pending)) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&vcp->vc_waitq, &wait); + + if (retval) + goto out; + + req = list_entry(vcp->vc_pending.next, struct upc_req,uc_chain); + list_del(&req->uc_chain); + + /* Move the input args into userspace */ + count = req->uc_inSize; + if (nbytes < req->uc_inSize) { printk ("psdev_read: Venus read %ld bytes of %d in message\n", - (long)count, req->uc_inSize); + (long)nbytes, req->uc_inSize); + count = nbytes; } - if ( copy_to_user(buf, req->uc_data, result)) - return -EFAULT; + if (copy_to_user(buf, req->uc_data, count)) { + retval = -EFAULT; + goto free_out; + } - /* If request was a signal, don't enqueue */ - if (req->uc_opcode == CODA_SIGNAL) { - CDEBUG(D_PSDEV, "vcread: signal msg (%d, %d)\n", - req->uc_opcode, req->uc_unique); - CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr)); - CODA_FREE(req, sizeof(struct upc_req)); - return count; - } - - req->uc_flags |= REQ_READ; - list_add(&(req->uc_chain), vcp->vc_processing.prev); + /* If request was not a signal, enqueue and don't free */ + if (req->uc_opcode != CODA_SIGNAL) { + req->uc_flags |= REQ_READ; + list_add(&(req->uc_chain), vcp->vc_processing.prev); + goto out; + } + + CDEBUG(D_PSDEV, "vcread: signal msg (%d, %d)\n", + req->uc_opcode, req->uc_unique); - return result; +free_out: + CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr)); + CODA_FREE(req, sizeof(struct upc_req)); +out: + unlock_kernel(); + return (count ? count : retval); } @@ -251,7 +292,7 @@ static int coda_psdev_open(struct inode * inode, struct file * file) ENTRY; /* first opener: must be lento. Initialize & take its pid */ - if ( file->f_flags == O_RDWR ) { + if ( (file->f_flags & O_ACCMODE) == O_RDWR ) { if ( vcp->vc_pid ) { printk("Venus pid already set to %d!!\n", vcp->vc_pid); return -1; @@ -264,7 +305,7 @@ static int coda_psdev_open(struct inode * inode, struct file * file) vcp->vc_inuse++; - if ( file->f_flags == O_RDWR ) { + if ( (file->f_flags & O_ACCMODE) == O_RDWR ) { vcp->vc_pid = current->pid; vcp->vc_seq = 0; INIT_LIST_HEAD(&vcp->vc_pending); @@ -334,6 +375,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file) static struct file_operations coda_psdev_fops = { + owner: THIS_MODULE, read: coda_psdev_read, write: coda_psdev_write, poll: coda_psdev_poll, diff --git a/fs/coda/stats.c b/fs/coda/stats.c deleted file mode 100644 index d4a8b2e9b..000000000 --- a/fs/coda/stats.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * stats.c - * - * CODA operation statistics - * - * (c) March, 1998 Zhanyong Wan <zhanyong.wan@yale.edu> - * - */ - -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/sysctl.h> -#include <linux/swapctl.h> -#include <linux/proc_fs.h> -#include <linux/malloc.h> -#include <linux/stat.h> -#include <linux/ctype.h> -#include <asm/bitops.h> -#include <asm/segment.h> -#include <asm/uaccess.h> -#include <linux/utsname.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_proc.h> - -struct coda_vfs_stats coda_vfs_stat; -struct coda_permission_stats coda_permission_stat; -struct coda_cache_inv_stats coda_cache_inv_stat; -struct coda_upcall_stats_entry coda_upcall_stat[CODA_NCALLS]; - -/* keep this in sync with coda.h! */ -char *coda_upcall_names[] = { - "totals ", /* 0 */ - "noop ", /* 1 */ - "root ", /* 2 */ - "sync ", /* 3 */ - "open ", /* 4 */ - "close ", /* 5 */ - "ioctl ", /* 6 */ - "getattr ", /* 7 */ - "setattr ", /* 8 */ - "access ", /* 9 */ - "lookup ", /* 10 */ - "create ", /* 11 */ - "remove ", /* 12 */ - "link ", /* 13 */ - "rename ", /* 14 */ - "mkdir ", /* 15 */ - "rmdir ", /* 16 */ - "readdir ", /* 17 */ - "symlink ", /* 18 */ - "readlink ", /* 19 */ - "fsync ", /* 20 */ - "inactive ", /* 21 */ - "vget ", /* 22 */ - "signal ", /* 23 */ - "replace ", /* 24 */ - "flush ", /* 25 */ - "purgeuser ", /* 26 */ - "zapfile ", /* 27 */ - "zapdir ", /* 28 */ - "zapvnode ", /* 28 */ - "purgefid ", /* 30 */ - "open_by_path" /* 31 */ -}; - - - - -void reset_coda_vfs_stats( void ) -{ - memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) ); -} - -#if 0 -static void reset_upcall_entry( struct coda_upcall_stats_entry * pentry ) -{ - pentry->count = 0; - pentry->time_sum = pentry->time_squared_sum = 0; -} -#endif - -void reset_coda_upcall_stats( void ) -{ - memset( &coda_upcall_stat, 0, sizeof( coda_upcall_stat ) ); -} - -void reset_coda_permission_stats( void ) -{ - memset( &coda_permission_stat, 0, sizeof( coda_permission_stat ) ); -} - -void reset_coda_cache_inv_stats( void ) -{ - memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) ); -} - - -void do_time_stats( struct coda_upcall_stats_entry * pentry, - unsigned long runtime ) -{ - - unsigned long time = runtime * 1000 /HZ; /* time in ms */ - CDEBUG(D_SPECIAL, "time: %ld\n", time); - - if ( pentry->count == 0 ) { - pentry->time_sum = pentry->time_squared_sum = 0; - } - - pentry->count++; - pentry->time_sum += time; - pentry->time_squared_sum += time*time; -} - - - -void coda_upcall_stats(int opcode, long unsigned runtime) -{ - struct coda_upcall_stats_entry * pentry; - - if ( opcode < 0 || opcode > CODA_NCALLS - 1) { - printk("Nasty opcode %d passed to coda_upcall_stats\n", - opcode); - return; - } - - pentry = &coda_upcall_stat[opcode]; - do_time_stats(pentry, runtime); - - /* fill in the totals */ - pentry = &coda_upcall_stat[0]; - do_time_stats(pentry, runtime); - -} - -unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry ) -{ - return ( pentry->count == 0 ) ? 0 : pentry->time_sum / pentry->count; -} - -static inline unsigned long absolute( unsigned long x ) -{ - return x >= 0 ? x : -x; -} - -static unsigned long sqr_root( unsigned long x ) -{ - unsigned long y = x, r; - int n_bit = 0; - - if ( x == 0 ) - return 0; - if ( x < 0) - x = -x; - - while ( y ) { - y >>= 1; - n_bit++; - } - - r = 1 << (n_bit/2); - - while ( 1 ) { - r = (r + x/r)/2; - if ( r*r <= x && x < (r+1)*(r+1) ) - break; - } - - return r; -} - -unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry ) -{ - unsigned long time_avg; - - if ( pentry->count <= 1 ) - return 0; - - time_avg = get_time_average( pentry ); - return - sqr_root( (pentry->time_squared_sum / pentry->count) - - time_avg * time_avg ); -} - -int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp, - void * buffer, size_t * lenp ) -{ - if ( write ) { - reset_coda_vfs_stats(); - } - - *lenp = 0; - return 0; -} - -int do_reset_coda_upcall_stats( ctl_table * table, int write, - struct file * filp, void * buffer, - size_t * lenp ) -{ - if ( write ) { - reset_coda_upcall_stats(); - } - - *lenp = 0; - return 0; -} - -int do_reset_coda_permission_stats( ctl_table * table, int write, - struct file * filp, void * buffer, - size_t * lenp ) -{ - if ( write ) { - reset_coda_permission_stats(); - } - - *lenp = 0; - return 0; -} - -int do_reset_coda_cache_inv_stats( ctl_table * table, int write, - struct file * filp, void * buffer, - size_t * lenp ) -{ - if ( write ) { - reset_coda_cache_inv_stats(); - } - - *lenp = 0; - return 0; -} - -int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset, - int length, int dummy ) -{ - int len=0; - off_t begin; - struct coda_vfs_stats * ps = & coda_vfs_stat; - - /* this works as long as we are below 1024 characters! */ - len += sprintf( buffer, - "Coda VFS statistics\n" - "===================\n\n" - "File Operations:\n" - "\tfile_read\t%9d\n" - "\tfile_write\t%9d\n" - "\tfile_mmap\t%9d\n" - "\topen\t\t%9d\n" - "\trelase\t\t%9d\n" - "\tfsync\t\t%9d\n\n" - "Dir Operations:\n" - "\treaddir\t\t%9d\n\n" - "Inode Operations\n" - "\tcreate\t\t%9d\n" - "\tlookup\t\t%9d\n" - "\tlink\t\t%9d\n" - "\tunlink\t\t%9d\n" - "\tsymlink\t\t%9d\n" - "\tmkdir\t\t%9d\n" - "\trmdir\t\t%9d\n" - "\trename\t\t%9d\n" - "\tpermission\t%9d\n" - "\treadpage\t%9d\n", - - /* file operations */ - ps->file_read, - ps->file_write, - ps->file_mmap, - ps->open, - ps->release, - ps->fsync, - - /* dir operations */ - ps->readdir, - - /* inode operations */ - ps->create, - ps->lookup, - ps->link, - ps->unlink, - ps->symlink, - ps->mkdir, - ps->rmdir, - ps->rename, - ps->permission, - ps->readpage ); - - begin = offset; - *start = buffer + begin; - len -= begin; - - if ( len > length ) - len = length; - if ( len < 0 ) - len = 0; - - return len; -} - -int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset, - int length, int dummy ) -{ - int len=0; - int i; - off_t begin; - off_t pos = 0; - char tmpbuf[80]; - int tmplen = 0; - - ENTRY; - /* this works as long as we are below 1024 characters! */ - if ( offset < 80 ) - len += sprintf( buffer,"%-79s\n", "Coda upcall statistics"); - if ( offset < 160) - len += sprintf( buffer + len,"%-79s\n", "======================"); - if ( offset < 240) - len += sprintf( buffer + len,"%-79s\n", "upcall\t\t count\tavg time(ms)\tstd deviation(ms)"); - if ( offset < 320) - len += sprintf( buffer + len,"%-79s\n", "------\t\t -----\t------------\t-----------------"); - pos = 320; - for ( i = 0 ; i < CODA_NCALLS ; i++ ) { - tmplen += sprintf(tmpbuf,"%s\t%9d\t%10ld\t%10ld", - coda_upcall_names[i], - coda_upcall_stat[i].count, - get_time_average(&coda_upcall_stat[i]), - coda_upcall_stat[i].time_squared_sum); - pos += 80; - if ( pos < offset ) - continue; - len += sprintf(buffer + len, "%-79s\n", tmpbuf); - if ( len >= length ) - break; - } - - begin = len- (pos - offset); - *start = buffer + begin; - len -= begin; - - if ( len > length ) - len = length; - if ( len < 0 ) - len = 0; - EXIT; - return len; -} - -int coda_permission_stats_get_info( char * buffer, char ** start, off_t offset, - int length, int dummy ) -{ - int len=0; - off_t begin; - struct coda_permission_stats * ps = & coda_permission_stat; - - /* this works as long as we are below 1024 characters! */ - len += sprintf( buffer, - "Coda permission statistics\n" - "==========================\n\n" - "count\t\t%9d\n" - "hit count\t%9d\n", - - ps->count, - ps->hit_count ); - - begin = offset; - *start = buffer + begin; - len -= begin; - - if ( len > length ) - len = length; - if ( len < 0 ) - len = 0; - - return len; -} - -int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset, - int length, int dummy ) -{ - int len=0; - off_t begin; - struct coda_cache_inv_stats * ps = & coda_cache_inv_stat; - - /* this works as long as we are below 1024 characters! */ - len += sprintf( buffer, - "Coda cache invalidation statistics\n" - "==================================\n\n" - "flush\t\t%9d\n" - "purge user\t%9d\n" - "zap_dir\t\t%9d\n" - "zap_file\t%9d\n" - "zap_vnode\t%9d\n" - "purge_fid\t%9d\n" - "replace\t\t%9d\n", - ps->flush, - ps->purge_user, - ps->zap_dir, - ps->zap_file, - ps->zap_vnode, - ps->purge_fid, - ps->replace ); - - begin = offset; - *start = buffer + begin; - len -= begin; - - if ( len > length ) - len = length; - if ( len < 0 ) - len = 0; - - return len; -} - diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c index 289f9417c..cbfff3e5b 100644 --- a/fs/coda/sysctl.c +++ b/fs/coda/sysctl.c @@ -297,9 +297,6 @@ int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset, "Coda VFS statistics\n" "===================\n\n" "File Operations:\n" - "\tfile_read\t%9d\n" - "\tfile_write\t%9d\n" - "\tfile_mmap\t%9d\n" "\topen\t\t%9d\n" "\trelase\t\t%9d\n" "\tfsync\t\t%9d\n\n" @@ -314,13 +311,9 @@ int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset, "\tmkdir\t\t%9d\n" "\trmdir\t\t%9d\n" "\trename\t\t%9d\n" - "\tpermission\t%9d\n" - "\treadpage\t%9d\n", + "\tpermission\t%9d\n", /* file operations */ - ps->file_read, - ps->file_write, - ps->file_mmap, ps->open, ps->release, ps->fsync, @@ -337,9 +330,8 @@ int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset, ps->mkdir, ps->rmdir, ps->rename, - ps->permission, - ps->readpage ); - + ps->permission); + begin = offset; *start = buffer + begin; len -= begin; diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 63586d05c..674c8cb3b 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -40,19 +40,31 @@ #include <linux/coda_proc.h> -static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize, +static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize, union inputArgs *buffer); +static void *alloc_upcall(int opcode, int size) +{ + union inputArgs *inp; + + CODA_ALLOC(inp, union inputArgs *, size); + if (!inp) + return ERR_PTR(-ENOMEM); + + inp->ih.opcode = opcode; + inp->ih.pid = current->pid; + inp->ih.pgid = current->pgrp; + coda_load_creds(&(inp->ih.cred)); + + return (void*)inp; +} + #define UPARG(op)\ do {\ - CODA_ALLOC(inp, union inputArgs *, insize);\ - if ( !inp ) { return -ENOMEM; }\ - 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;\ + inp = (union inputArgs *)alloc_upcall(op, insize); \ + if (IS_ERR(inp)) { return PTR_ERR(inp); }\ + outp = (union outputArgs *)(inp); \ + outsize = insize; \ } while (0) static inline int max(int a, int b) @@ -84,12 +96,12 @@ int venus_rootfid(struct super_block *sb, ViceFid *fidp) if (error) { printk("coda_get_rootfid: error %d\n", error); } else { - *fidp = (ViceFid) outp->coda_root.VFid; + *fidp = (ViceFid) outp->coda_root.VFid; CDEBUG(D_SUPER, "VolumeId: %lx, VnodeId: %lx.\n", fidp->Volume, fidp->Vnode); } - if (inp) CODA_FREE(inp, insize); + CODA_FREE(inp, insize); EXIT; return error; } @@ -108,11 +120,9 @@ int venus_getattr(struct super_block *sb, struct ViceFid *fid, error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if ( !error ) - *attr = outp->coda_getattr.attr; + *attr = outp->coda_getattr.attr; - if (inp) - CODA_FREE(inp, insize); + CODA_FREE(inp, insize); EXIT; return error; } @@ -124,7 +134,7 @@ int venus_setattr(struct super_block *sb, struct ViceFid *fid, union outputArgs *outp; int insize, outsize, error; - insize= SIZE(setattr); + insize = SIZE(setattr); UPARG(CODA_SETATTR); inp->coda_setattr.VFid = *fid; @@ -133,7 +143,7 @@ int venus_setattr(struct super_block *sb, struct ViceFid *fid, error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); CDEBUG(D_SUPER, " result %d\n", error); - if ( inp ) CODA_FREE(inp, insize); + CODA_FREE(inp, insize); return error; } @@ -147,7 +157,7 @@ int venus_lookup(struct super_block *sb, struct ViceFid *fid, int offset; offset = INSIZE(lookup); - insize = max(offset + length +1, OUTSIZE(lookup)); + insize = max(offset + length +1, OUTSIZE(lookup)); UPARG(CODA_LOOKUP); inp->coda_lookup.VFid = *fid; @@ -159,12 +169,10 @@ int venus_lookup(struct super_block *sb, struct ViceFid *fid, error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if ( !error ) { - *resfid = outp->coda_lookup.VFid; - *type = outp->coda_lookup.vtype; - } - if (inp) CODA_FREE(inp, insize); - + *resfid = outp->coda_lookup.VFid; + *type = outp->coda_lookup.vtype; + + CODA_FREE(inp, insize); return error; } @@ -189,8 +197,7 @@ int venus_release(struct super_block *sb, struct ViceFid *fid, int flags, error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if (inp) - CODA_FREE(inp, insize); + CODA_FREE(inp, insize); return error; } @@ -209,17 +216,10 @@ int venus_open(struct super_block *sb, struct ViceFid *fid, error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if ( !error ) { - *ino = outp->coda_open.inode; - *dev = outp->coda_open.dev; - } else { - *ino = 0; - *dev = 0; - } - - if (inp) - CODA_FREE(inp, insize); + *ino = outp->coda_open.inode; + *dev = outp->coda_open.dev; + CODA_FREE(inp, insize); return error; } @@ -248,8 +248,7 @@ int venus_mkdir(struct super_block *sb, struct ViceFid *dirfid, *attrs = outp->coda_mkdir.attr; *newfid = outp->coda_mkdir.VFid; - if (inp) - CODA_FREE(inp, insize); + CODA_FREE(inp, insize); return error; } @@ -289,7 +288,7 @@ int venus_rename(struct super_block *sb, struct ViceFid *old_fid, (char *)inp + (int) inp->coda_rename.destname); error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if (inp) CODA_FREE(inp, insize); + CODA_FREE(inp, insize); return error; } @@ -322,8 +321,7 @@ int venus_create(struct super_block *sb, struct ViceFid *dirfid, *attrs = outp->coda_create.attr; *newfid = outp->coda_create.VFid; - if (inp) - CODA_FREE(inp, insize); + CODA_FREE(inp, insize); return error; } @@ -345,8 +343,8 @@ int venus_rmdir(struct super_block *sb, struct ViceFid *dirfid, *((char *)inp + offset + length) = '\0'; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if ( inp ) - CODA_FREE(inp, insize); + + CODA_FREE(inp, insize); return error; } @@ -367,8 +365,8 @@ int venus_remove(struct super_block *sb, struct ViceFid *dirfid, *((char *)inp + offset + length) = '\0'; error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if ( inp ) - CODA_FREE(inp, insize); + + CODA_FREE(inp, insize); return error; } @@ -398,9 +396,9 @@ int venus_readlink(struct super_block *sb, struct ViceFid *fid, *(buffer + retlen) = '\0'; } - if (inp) CODA_FREE(inp, insize); CDEBUG(D_INODE, " result %d\n",error); EXIT; + CODA_FREE(inp, insize); return error; } @@ -428,10 +426,9 @@ int venus_link(struct super_block *sb, struct ViceFid *fid, error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if (inp) - CODA_FREE(inp, insize); CDEBUG(D_INODE, " result %d\n",error); EXIT; + CODA_FREE(inp, insize); return error; } @@ -466,10 +463,9 @@ int venus_symlink(struct super_block *sb, struct ViceFid *fid, error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if (inp) - CODA_FREE(inp, insize); CDEBUG(D_INODE, " result %d\n",error); EXIT; + CODA_FREE(inp, insize); return error; } @@ -486,8 +482,7 @@ int venus_fsync(struct super_block *sb, struct ViceFid *fid) error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs), &outsize, inp); - if ( inp ) - CODA_FREE(inp, insize); + CODA_FREE(inp, insize); return error; } @@ -505,7 +500,7 @@ int venus_access(struct super_block *sb, struct ViceFid *fid, int mask) error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); - if (inp) CODA_FREE(inp, insize); + CODA_FREE(inp, insize); EXIT; return error; } @@ -576,8 +571,7 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, } exit: - if (inp) - CODA_FREE(inp, insize); + CODA_FREE(inp, insize); return error; } @@ -602,9 +596,9 @@ int venus_statfs(struct super_block *sb, struct statfs *sfs) printk("coda_statfs: Venus returns: %d\n", error); } - if (inp) CODA_FREE(inp, insize); CDEBUG(D_INODE, " result %d\n",error); EXIT; + CODA_FREE(inp, insize); return error; } @@ -625,16 +619,20 @@ static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp) add_wait_queue(&vmp->uc_sleep, &wait); for (;;) { - if ( coda_hard == 0 ) + if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE ) set_current_state(TASK_INTERRUPTIBLE); else set_current_state(TASK_UNINTERRUPTIBLE); + /* venus died */ + if ( !coda_upc_comm.vc_pid ) + break; + /* got a reply */ if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) ) break; - if ( !coda_hard && signal_pending(current) ) { + if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) { /* if this process really wants to die, let it go */ if ( sigismember(&(current->signal), SIGKILL) || sigismember(&(current->signal), SIGINT) ) @@ -645,7 +643,6 @@ static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp) break; } schedule(); - } remove_wait_queue(&vmp->uc_sleep, &wait); current->state = TASK_RUNNING; @@ -711,6 +708,7 @@ ENTRY; /* Append msg to pending queue and poke Venus. */ list_add(&(req->uc_chain), vcommp->vc_pending.prev); + CDEBUG(D_UPCALL, "Proc %d wake Venus for(opc,uniq) =(%d,%d) msg at %p.zzz.\n", current->pid, req->uc_opcode, req->uc_unique, req); @@ -848,7 +846,7 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb) { /* Handle invalidation requests. */ if ( !sb || !sb->s_root || !sb->s_root->d_inode) { - printk("coda_downcall: opcode %d, no sb!\n", opcode); + CDEBUG(D_DOWNCALL, "coda_downcall: opcode %d, no sb!\n", opcode); return 0; } @@ -878,8 +876,7 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb) case CODA_ZAPDIR : { struct inode *inode; ViceFid *fid = &out->coda_zapdir.CodaFid; - CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", - coda_f2s(fid)); + CDEBUG(D_DOWNCALL, "zapdir: fid = %s...\n", coda_f2s(fid)); clstats(CODA_ZAPDIR); inode = coda_fid_to_inode(fid, sb); @@ -889,7 +886,7 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb) coda_flag_inode_children(inode, C_PURGE); CDEBUG(D_DOWNCALL, "zapdir: inode = %ld cache cleared\n", inode->i_ino); coda_flag_inode(inode, C_VATTR); - iput(inode); + iput(inode); } else CDEBUG(D_DOWNCALL, "zapdir: no inode\n"); @@ -900,14 +897,13 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb) struct inode *inode; struct ViceFid *fid = &out->coda_zapfile.CodaFid; clstats(CODA_ZAPFILE); - CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", - coda_f2s(fid)); + 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); + CDEBUG(D_DOWNCALL, "zapfile: inode = %ld\n", + inode->i_ino); coda_flag_inode(inode, C_VATTR); - iput(inode); + iput(inode); } else CDEBUG(D_DOWNCALL, "zapfile: no inode\n"); return 0; @@ -916,61 +912,20 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb) case CODA_PURGEFID : { struct inode *inode; ViceFid *fid = &out->coda_purgefid.CodaFid; - CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", - coda_f2s(fid)); + CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid)); clstats(CODA_PURGEFID); inode = coda_fid_to_inode(fid, sb); if ( inode ) { - CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n", - inode->i_ino); + CDEBUG(D_DOWNCALL, "purgefid: inode = %ld\n", + inode->i_ino); coda_flag_inode_children(inode, C_PURGE); coda_purge_dentries(inode); - iput(inode); - }else + iput(inode); + } else CDEBUG(D_DOWNCALL, "purgefid: no inode\n"); return 0; } - case CODA_MAKE_CINODE : { - struct inode *inode; - ViceFid *fid = &out->coda_make_cinode.CodaFid; - struct coda_vattr *attr = &out->coda_make_cinode.attr; - int fd = out->coda_make_cinode.fd; - struct file *file; - CDEBUG(D_DOWNCALL, "make_cinode: fid = %s, ino = %ld\n", - coda_f2s(fid), attr->va_fileid); - - inode = coda_iget(sb, fid, attr); - if ( !inode ) { - CDEBUG(D_DOWNCALL, "make_cinode: no inode\n"); - return -EINVAL; - } - - file = fget(fd); - if ( !file ) { - CDEBUG(D_DOWNCALL, "make_cinode: no file\n"); - iput(inode); - return -EINVAL; - } - - inode->u.coda_i.c_ovp = file->f_dentry->d_inode; - inode->i_mapping = file->f_dentry->d_inode->i_mapping; - file->f_dentry->d_inode = inode; - file->f_op = &coda_file_operations; - - /* - Unhash the dentry of the container file, as it is - still owned by the fs that stores the container - file. A more reliable solution would be to create - an new dentry owned by Coda, but that would require - knowledge of the internals of the dcache. - */ - d_drop(file->f_dentry); - - fput(file); - return 0; - } - case CODA_REPLACE : { struct inode *inode; ViceFid *oldfid = &out->coda_replace.OldFid; @@ -979,9 +934,10 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb) CDEBUG(D_DOWNCALL, "CODA_REPLACE\n"); inode = coda_fid_to_inode(oldfid, sb); if ( inode ) { - CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n", inode->i_ino); + CDEBUG(D_DOWNCALL, "replacefid: inode = %ld\n", + inode->i_ino); coda_replace_fid(inode, oldfid, newfid); - iput(inode); + iput(inode); }else CDEBUG(D_DOWNCALL, "purgefid: no inode\n"); |