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