Commit dbd82204 authored by Jan Harkes's avatar Jan Harkes Committed by Linus Torvalds

[PATCH] Coda FS update

Most of these changes have been tested and used in the 2.4 tree, so this
is mostly a forward port of 2.4 bugfixes.

* C99 initializers
* Added specific initializations instead of assuming that the private
  part of the inode is already initialized.
* Remove unused code.
* Moved container file to the struct file private data, this is to
* correct the session semantics model when file updates are fetched from
* the server (old 'sessions' shouldn't see the new container yet).
* Fixed consistency (and occasional oopes) when mmap-ing Coda files.
* Fixing up inode numbers in readdir, old libc5 getcwd was broken.
* Nuked upcall_stats, all of this can easily be maintained in userspace,
  and the existing code suffers from overflows in the fixed point
  calculations.
parent 7570df54
......@@ -26,9 +26,9 @@ inline int coda_isnullfid(ViceFid *fid)
}
static struct inode_operations coda_symlink_inode_operations = {
readlink: page_readlink,
follow_link: page_follow_link,
setattr: coda_setattr,
.readlink = page_readlink,
.follow_link = page_follow_link,
.setattr = coda_setattr,
};
/* cnode.c */
......@@ -85,6 +85,7 @@ struct inode * coda_iget(struct super_block * sb, ViceFid * fid,
cii = ITOC(inode);
/* we still need to set i_ino for things like stat(2) */
inode->i_ino = hash;
cii->c_mapcount = 0;
list_add(&cii->c_cilist, &sbi->sbi_cihead);
unlock_new_inode(inode);
}
......
......@@ -29,21 +29,7 @@ int coda_fake_statfs;
char * coda_f2s(ViceFid *f)
{
static char s[60];
if ( f ) {
sprintf(s, "(%-#lx,%-#lx,%-#lx)",
f->Volume, f->Vnode, f->Unique);
}
return s;
}
/* print another fid */
char * coda_f2s2(ViceFid *f)
{
static char s[60];
if ( f ) {
sprintf(s, "(%-#lx,%-#lx,%-#lx)",
f->Volume, f->Vnode, f->Unique);
}
sprintf(s, "(%-#lx.%-#lx.%-#lx)", f->Volume, f->Vnode, f->Unique);
return s;
}
......
......@@ -49,40 +49,42 @@ static int coda_dentry_revalidate(struct dentry *de, int);
static int coda_dentry_delete(struct dentry *);
/* support routines */
static int coda_venus_readdir(struct file *filp, filldir_t filldir, void *dirent);
static int coda_venus_readdir(struct file *filp, filldir_t filldir,
void *dirent, struct dentry *dir);
int coda_fsync(struct file *, struct dentry *dentry, int datasync);
int coda_hasmknod;
struct dentry_operations coda_dentry_operations =
{
d_revalidate: coda_dentry_revalidate,
d_delete: coda_dentry_delete,
.d_revalidate = coda_dentry_revalidate,
.d_delete = coda_dentry_delete,
};
struct inode_operations coda_dir_inode_operations =
{
create: coda_create,
lookup: coda_lookup,
link: coda_link,
unlink: coda_unlink,
symlink: coda_symlink,
mkdir: coda_mkdir,
rmdir: coda_rmdir,
mknod: coda_mknod,
rename: coda_rename,
permission: coda_permission,
getattr: coda_getattr,
setattr: coda_setattr,
.create = coda_create,
.lookup = coda_lookup,
.link = coda_link,
.unlink = coda_unlink,
.symlink = coda_symlink,
.mkdir = coda_mkdir,
.rmdir = coda_rmdir,
.mknod = coda_mknod,
.rename = coda_rename,
.permission = coda_permission,
.getattr = coda_getattr,
.setattr = coda_setattr,
};
struct file_operations coda_dir_operations = {
read: generic_read_dir,
readdir: coda_readdir,
open: coda_open,
flush: coda_flush,
release: coda_release,
fsync: coda_fsync,
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = coda_readdir,
.open = coda_open,
.flush = coda_flush,
.release = coda_release,
.fsync = coda_fsync,
};
......@@ -477,31 +479,42 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
/* file operations for directories */
int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir)
{
int result = 0;
struct dentry *coda_dentry = coda_file->f_dentry;
struct inode *coda_inode = coda_dentry->d_inode;
struct coda_inode_info *cii = ITOC(coda_inode);
struct file *host_file = cii->c_container;
struct coda_file_info *cfi;
struct file *host_file;
struct inode *host_inode;
int ret;
BUG_ON(!host_file);
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
host_file = cfi->cfi_container;
coda_vfs_stat.readdir++;
/* Access to both host and coda f_pos fields is serialized on the
* coda_file->f_dentry->d_inode->i_sem which has already been taken by
* vfs_readdir. Userspace shouldn't 'play' with the container file as
* long as the file is held open. */
host_inode = host_file->f_dentry->d_inode;
down(&host_inode->i_sem);
host_file->f_pos = coda_file->f_pos;
if ( !host_file->f_op->readdir )
if (!host_file->f_op->readdir) {
/* Venus: we must read Venus dirents from the file */
result = coda_venus_readdir(host_file, filldir, dirent);
else
/* potemkin case: we were handed a directory inode */
result = vfs_readdir(host_file, filldir, dirent);
ret = coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
} else {
/* potemkin case: we were handed a directory inode. */
/* Yuk, we can't call vfs_readdir because we are already
* holding the inode semaphore. */
ret = -ENOTDIR;
if (!host_file->f_op || !host_file->f_op->readdir)
goto out;
ret = -ENOENT;
if (!IS_DEADDIR(host_inode))
ret = host_file->f_op->readdir(host_file, filldir, dirent);
}
out:
coda_file->f_pos = host_file->f_pos;
return result;
up(&host_inode->i_sem);
return ret;
}
static inline unsigned int CDT2DT(unsigned char cdt)
......@@ -525,20 +538,38 @@ static inline unsigned int CDT2DT(unsigned char cdt)
/* support routines */
static int coda_venus_readdir(struct file *filp, filldir_t filldir,
void *getdent)
void *dirent, struct dentry *dir)
{
int result = 0; /* # of entries returned */
struct venus_dirent *vdir;
unsigned long vdir_size =
(unsigned long)(&((struct venus_dirent *)0)->d_name);
int ret;
unsigned int type;
struct qstr name;
ino_t ino;
int ret, i;
vdir = (struct venus_dirent *)kmalloc(sizeof(*vdir), GFP_KERNEL);
if (!vdir) return -ENOMEM;
while(1) {
/* we use this routine to read the file into our buffer */
ret = kernel_read(filp, filp->f_pos, (char *)vdir,
i = filp->f_pos;
switch(i) {
case 0:
ret = filldir(dirent, ".", 1, 0, dir->d_inode->i_ino, DT_DIR);
if (ret < 0) break;
result++;
filp->f_pos++;
/* fallthrough */
case 1:
ret = filldir(dirent, "..", 2, 1, dir->d_parent->d_inode->i_ino, DT_DIR);
if (ret < 0) break;
result++;
filp->f_pos++;
/* fallthrough */
default:
while (1) {
/* read entries from the directory file */
ret = kernel_read(filp, filp->f_pos - 2, (char *)vdir,
sizeof(*vdir));
if (ret < 0) {
printk("coda_venus_readdir: read dir failed %d\n", ret);
......@@ -556,17 +587,32 @@ static int coda_venus_readdir(struct file *filp, filldir_t filldir,
/* validate whether the directory file actually makes sense */
if (vdir->d_reclen < vdir_size + vdir->d_namlen ||
vdir->d_namlen > CODA_MAXNAMLEN) {
printk("coda_venus_readdir: Invalid directory: %ld\n",
printk("coda_venus_readdir: Invalid dir: %ld\n",
filp->f_dentry->d_inode->i_ino);
ret = -EBADF;
break;
}
name.len = vdir->d_namlen;
name.name = vdir->d_name;
/* Make sure we skip '.' and '..', we already got those */
if (name.name[0] == '.' && (name.len == 1 ||
(vdir->d_name[1] == '.' && name.len == 2)))
vdir->d_fileno = name.len = 0;
/* skip null entries */
if (vdir->d_fileno) {
unsigned int d_type = CDT2DT(vdir->d_type);
ret = filldir(getdent, vdir->d_name, vdir->d_namlen,
filp->f_pos, vdir->d_fileno, d_type);
if (vdir->d_fileno && name.len) {
/* try to look up this entry in the dcache, that way
* userspace doesn't have to worry about breaking
* getcwd by having mismatched inode numbers for
* internal volume mountpoints. */
ino = find_inode_number(dir, &name);
if (!ino) ino = vdir->d_fileno;
type = CDT2DT(vdir->d_type);
ret = filldir(dirent, name.name, name.len, filp->f_pos,
ino, type);
/* failure means no space for filling in this round */
if (ret < 0) break;
result++;
......@@ -575,6 +621,7 @@ static int coda_venus_readdir(struct file *filp, filldir_t filldir,
* we've already established it is non-zero. */
filp->f_pos += vdir->d_reclen;
}
}
kfree(vdir);
return result ? result : ret;
}
......@@ -660,7 +707,7 @@ int coda_revalidate_inode(struct dentry *dentry)
if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
if ( error )
goto return_bad_inode;
goto return_bad;
/* this inode may be lost if:
- it's ino changed
......@@ -679,7 +726,7 @@ int coda_revalidate_inode(struct dentry *dentry)
/* the following can happen when a local fid is replaced
with a global one, here we lose and declare the inode bad */
if (inode->i_ino != old_ino)
goto return_bad_inode;
goto return_bad;
coda_flag_inode_children(inode, C_FLUSH);
cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
......@@ -689,13 +736,7 @@ int coda_revalidate_inode(struct dentry *dentry)
unlock_kernel();
return 0;
return_bad_inode:
inode->i_mapping = &inode->i_data;
if (cii->c_container) {
fput(cii->c_container);
cii->c_container = NULL;
}
make_bad_inode(inode);
return_bad:
unlock_kernel();
return -EIO;
}
......
......@@ -29,143 +29,152 @@
int use_coda_close;
static ssize_t
coda_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
coda_file_read(struct file *coda_file, char *buf, size_t count, loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
struct coda_inode_info *cii = ITOC(inode);
struct file *cfile;
struct coda_file_info *cfi;
struct file *host_file;
cfile = cii->c_container;
if (!cfile) BUG();
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
host_file = cfi->cfi_container;
if (!cfile->f_op || !cfile->f_op->read)
if (!host_file->f_op || !host_file->f_op->read)
return -EINVAL;
return cfile->f_op->read(cfile, buf, count, ppos);
return host_file->f_op->read(host_file, buf, count, ppos);
}
static ssize_t
coda_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
coda_file_write(struct file *coda_file, const char *buf, size_t count, loff_t *ppos)
{
struct inode *cinode, *inode = file->f_dentry->d_inode;
struct coda_inode_info *cii = ITOC(inode);
struct file *cfile;
struct inode *host_inode, *coda_inode = coda_file->f_dentry->d_inode;
struct coda_file_info *cfi;
struct file *host_file;
ssize_t ret;
int flags;
cfile = cii->c_container;
if (!cfile) BUG();
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
host_file = cfi->cfi_container;
if (!cfile->f_op || !cfile->f_op->write)
if (!host_file->f_op || !host_file->f_op->write)
return -EINVAL;
cinode = cfile->f_dentry->d_inode;
down(&inode->i_sem);
flags = cfile->f_flags;
cfile->f_flags |= file->f_flags & (O_APPEND | O_SYNC);
host_inode = host_file->f_dentry->d_inode;
down(&coda_inode->i_sem);
ret = cfile->f_op->write(cfile, buf, count, ppos);
ret = host_file->f_op->write(host_file, buf, count, ppos);
cfile->f_flags = flags;
inode->i_size = cinode->i_size;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
up(&inode->i_sem);
coda_inode->i_size = host_inode->i_size;
coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
coda_inode->i_mtime = coda_inode->i_ctime = CURRENT_TIME;
up(&coda_inode->i_sem);
return ret;
}
static int
coda_file_mmap(struct file *file, struct vm_area_struct *vma)
coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
{
struct inode *inode = file->f_dentry->d_inode;
struct coda_inode_info *cii = ITOC(inode);
struct file *cfile;
cfile = cii->c_container;
struct coda_file_info *cfi;
struct coda_inode_info *cii;
struct file *host_file;
struct inode *coda_inode, *host_inode;
if (!cfile) BUG();
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
host_file = cfi->cfi_container;
if (!cfile->f_op || !cfile->f_op->mmap)
if (!host_file->f_op || !host_file->f_op->mmap)
return -ENODEV;
return cfile->f_op->mmap(cfile, vma);
coda_inode = coda_file->f_dentry->d_inode;
host_inode = host_file->f_dentry->d_inode;
if (coda_inode->i_mapping == &coda_inode->i_data)
coda_inode->i_mapping = host_inode->i_mapping;
/* only allow additional mmaps as long as userspace isn't changing
* the container file on us! */
else if (coda_inode->i_mapping != host_inode->i_mapping)
return -EBUSY;
/* keep track of how often the coda_inode/host_file has been mmapped */
cii = ITOC(coda_inode);
cii->c_mapcount++;
cfi->cfi_mapcount++;
return host_file->f_op->mmap(host_file, vma);
}
int coda_open(struct inode *i, struct file *f)
int coda_open(struct inode *coda_inode, struct file *coda_file)
{
struct file *fh = NULL;
int error = 0;
unsigned short flags = f->f_flags & (~O_EXCL);
struct file *host_file = NULL;
int error;
unsigned short flags = coda_file->f_flags & (~O_EXCL);
unsigned short coda_flags = coda_flags_to_cflags(flags);
struct coda_cred *cred;
struct coda_inode_info *cii;
struct coda_file_info *cfi;
lock_kernel();
coda_vfs_stat.open++;
error = venus_open(i->i_sb, coda_i2f(i), coda_flags, &fh);
if (error || !fh) {
cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL);
if (!cfi) {
unlock_kernel();
return error;
return -ENOMEM;
}
/* coda_upcall returns filehandle of container file object */
cii = ITOC(i);
if (cii->c_container)
fput(cii->c_container);
lock_kernel();
cii->c_contcount++;
cii->c_container = fh;
i->i_mapping = &cii->c_container->f_dentry->d_inode->i_data;
error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
&host_file);
if (error || !host_file) {
kfree(cfi);
unlock_kernel();
return error;
}
cred = kmalloc(sizeof(struct coda_cred), GFP_KERNEL);
host_file->f_flags |= coda_file->f_flags & (O_APPEND | O_SYNC);
/* If the allocation failed, we'll just muddle on. This actually works
* fine for normal cases. (i.e. when open credentials are the same as
* close credentials) */
if (cred) {
coda_load_creds(cred);
f->private_data = cred;
}
cfi->cfi_magic = CODA_MAGIC;
cfi->cfi_mapcount = 0;
cfi->cfi_container = host_file;
coda_load_creds(&cfi->cfi_cred);
BUG_ON(coda_file->private_data != NULL);
coda_file->private_data = cfi;
unlock_kernel();
return 0;
}
int coda_flush(struct file *file)
int coda_flush(struct file *coda_file)
{
unsigned short flags = (file->f_flags) & (~O_EXCL);
unsigned short cflags;
struct coda_inode_info *cii;
struct file *cfile;
struct inode *cinode, *inode;
unsigned short flags = coda_file->f_flags & ~O_EXCL;
unsigned short coda_flags = coda_flags_to_cflags(flags);
struct coda_file_info *cfi;
struct inode *coda_inode;
int err = 0, fcnt;
coda_vfs_stat.flush++;
/* last close semantics */
fcnt = file_count(coda_file);
if (fcnt > 1) return 0;
/* No need to make an upcall when we have not made any modifications
* to the file */
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
if ((coda_file->f_flags & O_ACCMODE) == O_RDONLY)
return 0;
if (use_coda_close)
return 0;
fcnt = file_count(file);
if (fcnt > 1) return 0;
cflags = coda_flags_to_cflags(flags);
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
inode = file->f_dentry->d_inode;
cii = ITOC(inode);
cfile = cii->c_container;
if (!cfile) BUG();
coda_inode = coda_file->f_dentry->d_inode;
cinode = cfile->f_dentry->d_inode;
err = venus_store(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
&cfi->cfi_cred);
err = venus_store(inode->i_sb, coda_i2f(inode), cflags,
(struct coda_cred *)file->private_data);
if (err == -EOPNOTSUPP) {
use_coda_close = 1;
err = 0;
......@@ -174,79 +183,81 @@ int coda_flush(struct file *file)
return err;
}
int coda_release(struct inode *i, struct file *f)
int coda_release(struct inode *coda_inode, struct file *coda_file)
{
unsigned short flags = (f->f_flags) & (~O_EXCL);
unsigned short cflags = coda_flags_to_cflags(flags);
unsigned short flags = (coda_file->f_flags) & (~O_EXCL);
unsigned short coda_flags = coda_flags_to_cflags(flags);
struct coda_file_info *cfi;
struct coda_inode_info *cii;
struct file *cfile;
struct inode *host_inode;
int err = 0;
lock_kernel();
coda_vfs_stat.release++;
if (!use_coda_close) {
err = venus_release(i->i_sb, coda_i2f(i), cflags);
err = venus_release(coda_inode->i_sb, coda_i2f(coda_inode),
coda_flags);
if (err == -EOPNOTSUPP) {
use_coda_close = 1;
err = 0;
}
}
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
if (use_coda_close)
err = venus_close(i->i_sb, coda_i2f(i), cflags,
(struct coda_cred *)f->private_data);
err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
coda_flags, &cfi->cfi_cred);
cii = ITOC(i);
cfile = cii->c_container;
if (!cfile) BUG();
host_inode = cfi->cfi_container->f_dentry->d_inode;
cii = ITOC(coda_inode);
if (--cii->c_contcount) {
unlock_kernel();
return err;
/* did we mmap this file? */
if (coda_inode->i_mapping == &host_inode->i_data) {
cii->c_mapcount -= cfi->cfi_mapcount;
if (!cii->c_mapcount)
coda_inode->i_mapping = &coda_inode->i_data;
}
i->i_mapping = &i->i_data;
fput(cfile);
cii->c_container = NULL;
if (f->private_data) {
kfree(f->private_data);
f->private_data = NULL;
}
fput(cfi->cfi_container);
kfree(coda_file->private_data);
coda_file->private_data = NULL;
unlock_kernel();
return err;
}
int coda_fsync(struct file *file, struct dentry *dentry, int datasync)
int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
{
struct file *cfile;
struct dentry *cdentry;
struct inode *cinode, *inode = dentry->d_inode;
struct coda_inode_info *cii = ITOC(inode);
struct file *host_file;
struct dentry *host_dentry;
struct inode *host_inode, *coda_inode = coda_dentry->d_inode;
struct coda_file_info *cfi;
int err = 0;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
S_ISLNK(coda_inode->i_mode)))
return -EINVAL;
cfile = cii->c_container;
if (!cfile) BUG();
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
host_file = cfi->cfi_container;
coda_vfs_stat.fsync++;
if (cfile->f_op && cfile->f_op->fsync) {
cdentry = cfile->f_dentry;
cinode = cdentry->d_inode;
down(&cinode->i_sem);
err = cfile->f_op->fsync(cfile, cdentry, datasync);
up(&cinode->i_sem);
if (host_file->f_op && host_file->f_op->fsync) {
host_dentry = host_file->f_dentry;
host_inode = host_dentry->d_inode;
down(&host_inode->i_sem);
err = host_file->f_op->fsync(host_file, host_dentry, datasync);
up(&host_inode->i_sem);
}
if ( !err && !datasync ) {
lock_kernel();
err = venus_fsync(inode->i_sb, coda_i2f(inode));
err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
unlock_kernel();
}
......@@ -254,13 +265,13 @@ int coda_fsync(struct file *file, struct dentry *dentry, int datasync)
}
struct file_operations coda_file_operations = {
llseek: generic_file_llseek,
read: coda_file_read,
write: coda_file_write,
mmap: coda_file_mmap,
open: coda_open,
flush: coda_flush,
release: coda_release,
fsync: coda_fsync,
.llseek = generic_file_llseek,
.read = coda_file_read,
.write = coda_file_write,
.mmap = coda_file_mmap,
.open = coda_open,
.flush = coda_flush,
.release = coda_release,
.fsync = coda_fsync,
};
......@@ -8,7 +8,6 @@
* Copyright (C) Carnegie Mellon University
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
......@@ -47,8 +46,6 @@ static struct inode *coda_alloc_inode(struct super_block *sb)
memset(&ei->c_fid, 0, sizeof(struct ViceFid));
ei->c_flags = 0;
INIT_LIST_HEAD(&ei->c_cilist);
ei->c_container = NULL;
ei->c_contcount = 0;
memset(&ei->c_cached_cred, 0, sizeof(struct coda_cred));
ei->c_cached_perm = 0;
return &ei->vfs_inode;
......@@ -88,11 +85,11 @@ void coda_destroy_inodecache(void)
/* exported operations */
struct super_operations coda_super_operations =
{
alloc_inode: coda_alloc_inode,
destroy_inode: coda_destroy_inode,
clear_inode: coda_clear_inode,
put_super: coda_put_super,
statfs: coda_statfs,
.alloc_inode = coda_alloc_inode,
.destroy_inode = coda_destroy_inode,
.clear_inode = coda_clear_inode,
.put_super = coda_put_super,
.statfs = coda_statfs,
};
static int get_device_index(struct coda_mount_data *data)
......@@ -230,10 +227,7 @@ static void coda_clear_inode(struct inode *inode)
{
struct coda_inode_info *cii = ITOC(inode);
if (cii->c_container) BUG();
list_del_init(&cii->c_cilist);
inode->i_mapping = &inode->i_data;
coda_cache_clear_inode(inode);
}
......@@ -273,9 +267,9 @@ int coda_setattr(struct dentry *de, struct iattr *iattr)
}
struct inode_operations coda_file_inode_operations = {
permission: coda_permission,
getattr: coda_getattr,
setattr: coda_setattr,
.permission = coda_permission,
.getattr = coda_getattr,
.setattr = coda_setattr,
};
static int coda_statfs(struct super_block *sb, struct statfs *buf)
......@@ -314,8 +308,9 @@ static struct super_block *coda_get_sb(struct file_system_type *fs_type,
}
struct file_system_type coda_fs_type = {
owner: THIS_MODULE,
name: "coda",
get_sb: coda_get_sb,
kill_sb: kill_anon_super,
.owner = THIS_MODULE,
.name = "coda",
.get_sb = coda_get_sb,
.kill_sb = kill_anon_super,
};
......@@ -14,7 +14,6 @@
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/string.h>
#define __NO_VERSION__
#include <linux/namei.h>
#include <linux/module.h>
#include <asm/uaccess.h>
......@@ -32,13 +31,13 @@ static int coda_pioctl(struct inode * inode, struct file * filp,
/* exported from this file */
struct inode_operations coda_ioctl_inode_operations =
{
permission: coda_ioctl_permission,
setattr: coda_setattr,
.permission = coda_ioctl_permission,
.setattr = coda_setattr,
};
struct file_operations coda_ioctl_operations = {
owner: THIS_MODULE,
ioctl: coda_pioctl,
.owner = THIS_MODULE,
.ioctl = coda_pioctl,
};
/* the coda pioctl inode ops */
......
......@@ -353,13 +353,13 @@ 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,
ioctl: coda_psdev_ioctl,
open: coda_psdev_open,
release: coda_psdev_release,
.owner = THIS_MODULE,
.read = coda_psdev_read,
.write = coda_psdev_write,
.poll = coda_psdev_poll,
.ioctl = coda_psdev_ioctl,
.open = coda_psdev_open,
.release = coda_psdev_release,
};
static devfs_handle_t devfs_handle;
......
......@@ -51,5 +51,5 @@ static int coda_symlink_filler(struct file *file, struct page *page)
}
struct address_space_operations coda_symlink_aops = {
readpage: coda_symlink_filler
.readpage = coda_symlink_filler,
};
......@@ -22,7 +22,6 @@
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <linux/utsname.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/coda.h>
......@@ -39,7 +38,6 @@ static struct ctl_table_header *fs_table_header;
#define CODA_TIMEOUT 3 /* timeout on upcalls to become intrble */
#define CODA_HARD 5 /* mount type "hard" or "soft" */
#define CODA_VFS 6 /* vfs statistics */
#define CODA_UPCALL 7 /* upcall statistics */
#define CODA_CACHE_INV 9 /* cache invalidation statistics */
#define CODA_FAKE_STATFS 10 /* don't query venus for actual cache usage */
......@@ -47,7 +45,6 @@ static ctl_table coda_table[] = {
{CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &proc_dointvec},
{CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &proc_dointvec},
{CODA_VFS, "vfs_stats", NULL, 0, 0644, NULL, &do_reset_coda_vfs_stats},
{CODA_UPCALL, "upcall_stats", NULL, 0, 0644, NULL, &do_reset_coda_upcall_stats},
{CODA_CACHE_INV, "cache_inv_stats", NULL, 0, 0644, NULL, &do_reset_coda_cache_inv_stats},
{CODA_FAKE_STATFS, "fake_statfs", &coda_fake_statfs, sizeof(int), 0600, NULL, &proc_dointvec},
{ 0 }
......@@ -60,152 +57,17 @@ static ctl_table fs_table[] = {
struct coda_vfs_stats coda_vfs_stat;
struct coda_cache_inv_stats coda_cache_inv_stat;
struct coda_upcall_stats_entry coda_upcall_stat[CODA_NCALLS];
struct coda_upcallstats coda_callstats;
int coda_upcall_timestamping = 0;
/* keep this in sync with coda.h! */
char *coda_upcall_names[] = {
"totals ", /* 0 */
"- ", /* 1 */
"root ", /* 2 */
"open_by_fd ", /* 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 */
"- ", /* 21 */
"vget ", /* 22 */
"signal ", /* 23 */
"replace ", /* 24 */
"flush ", /* 25 */
"purgeuser ", /* 26 */
"zapfile ", /* 27 */
"zapdir ", /* 28 */
"- ", /* 29 */
"purgefid ", /* 30 */
"open_by_path", /* 31 */
"resolve ", /* 32 */
"reintegrate ", /* 33 */
"statfs ", /* 34 */
"store ", /* 35 */
"release " /* 36 */
};
void reset_coda_vfs_stats( void )
{
memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
}
void reset_coda_upcall_stats( void )
{
memset( &coda_upcall_stat, 0, sizeof( coda_upcall_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; /* time in us */
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 )
{
......@@ -220,27 +82,6 @@ int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
return 0;
}
int do_reset_coda_upcall_stats( ctl_table * table, int write,
struct file * filp, void * buffer,
size_t * lenp )
{
if ( write ) {
if (*lenp > 0) {
char c;
if (get_user(c, (char *)buffer))
return -EFAULT;
coda_upcall_timestamping = (c == '1');
}
reset_coda_upcall_stats();
filp->f_pos += *lenp;
} else {
*lenp = 0;
}
return 0;
}
int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
struct file * filp, void * buffer,
size_t * lenp )
......@@ -317,52 +158,6 @@ int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset,
return len;
}
int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
int length)
{
int len=0;
int i;
off_t begin;
off_t pos = 0;
char tmpbuf[80];
int tmplen = 0;
/* 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 count avg time(us) std deviation(us)");
if ( offset < 320)
len += sprintf( buffer + len,"%-79s\n", "------ ----- ------------ -----------------");
pos = 320;
for ( i = 0 ; i < CODA_NCALLS ; i++ ) {
tmplen += sprintf(tmpbuf,"%s %9d %10ld %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;
return len;
}
int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
int length)
{
......@@ -421,9 +216,7 @@ struct proc_dir_entry* proc_fs_coda;
void coda_sysctl_init()
{
memset(&coda_callstats, 0, sizeof(coda_callstats));
reset_coda_vfs_stats();
reset_coda_upcall_stats();
reset_coda_cache_inv_stats();
#ifdef CONFIG_PROC_FS
......@@ -431,7 +224,6 @@ void coda_sysctl_init()
if (proc_fs_coda) {
proc_fs_coda->owner = THIS_MODULE;
coda_proc_create("vfs_stats", coda_vfs_stats_get_info);
coda_proc_create("upcall_stats", coda_upcall_stats_get_info);
coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info);
}
#endif
......@@ -454,7 +246,6 @@ void coda_sysctl_clean()
#if CONFIG_PROC_FS
remove_proc_entry("cache_inv_stats", proc_fs_coda);
remove_proc_entry("upcall_stats", proc_fs_coda);
remove_proc_entry("vfs_stats", proc_fs_coda);
remove_proc_entry("coda", proc_root_fs);
#endif
......
......@@ -171,10 +171,7 @@ int venus_store(struct super_block *sb, struct ViceFid *fid, int flags,
insize = SIZE(store);
UPARG(CODA_STORE);
if ( cred ) {
memcpy(&(inp->ih.cred), cred, sizeof(*cred));
} else
printk("CODA: store without valid file creds.\n");
inp->coda_store.VFid = *fid;
inp->coda_store.flags = flags;
......@@ -213,10 +210,7 @@ int venus_close(struct super_block *sb, struct ViceFid *fid, int flags,
insize = SIZE(release);
UPARG(CODA_CLOSE);
if ( cred ) {
memcpy(&(inp->ih.cred), cred, sizeof(*cred));
} else
printk("CODA: close without valid file creds.\n");
inp->coda_close.VFid = *fid;
inp->coda_close.flags = flags;
......@@ -620,17 +614,13 @@ int venus_statfs(struct super_block *sb, struct statfs *sfs)
*
*/
static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
static inline void coda_waitfor_upcall(struct upc_req *vmp,
struct venus_comm *vcommp)
{
DECLARE_WAITQUEUE(wait, current);
struct timeval begin = { 0, 0 }, end = { 0, 0 };
vmp->uc_posttime = jiffies;
if (coda_upcall_timestamping)
do_gettimeofday(&begin);
add_wait_queue(&vmp->uc_sleep, &wait);
for (;;) {
if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
......@@ -661,17 +651,7 @@ static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
remove_wait_queue(&vmp->uc_sleep, &wait);
set_current_state(TASK_RUNNING);
if (coda_upcall_timestamping && begin.tv_sec != 0) {
do_gettimeofday(&end);
if (end.tv_usec < begin.tv_usec) {
end.tv_usec += 1000000; end.tv_sec--;
}
end.tv_sec -= begin.tv_sec;
end.tv_usec -= begin.tv_usec;
}
return ((end.tv_sec * 1000000) + end.tv_usec);
return;
}
......@@ -689,7 +669,6 @@ static int coda_upcall(struct coda_sb_info *sbi,
int inSize, int *outSize,
union inputArgs *buffer)
{
unsigned long runtime;
struct venus_comm *vcommp;
union outputArgs *out;
struct upc_req *req;
......@@ -732,8 +711,7 @@ static int coda_upcall(struct coda_sb_info *sbi,
* ENODEV. */
/* Go to sleep. Wake up on signals only after the timeout. */
runtime = coda_waitfor_upcall(req, vcommp);
coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime);
coda_waitfor_upcall(req, vcommp);
if (vcommp->vc_inuse) { /* i.e. Venus is still alive */
/* Op went through, interrupt or not... */
......@@ -794,8 +772,6 @@ static int coda_upcall(struct coda_sb_info *sbi,
exit:
upc_free(req);
if (error)
badclstats();
return error;
}
......@@ -842,7 +818,6 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
switch (opcode) {
case CODA_FLUSH : {
clstats(CODA_FLUSH);
coda_cache_clear_all(sb, NULL);
shrink_dcache_sb(sb);
coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
......@@ -855,7 +830,6 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
printk("PURGEUSER: null cred!\n");
return 0;
}
clstats(CODA_PURGEUSER);
coda_cache_clear_all(sb, cred);
return(0);
}
......@@ -863,7 +837,6 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
case CODA_ZAPDIR : {
struct inode *inode;
ViceFid *fid = &out->coda_zapdir.CodaFid;
clstats(CODA_ZAPDIR);
inode = coda_fid_to_inode(fid, sb);
if (inode) {
......@@ -878,7 +851,6 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
case CODA_ZAPFILE : {
struct inode *inode;
struct ViceFid *fid = &out->coda_zapfile.CodaFid;
clstats(CODA_ZAPFILE);
inode = coda_fid_to_inode(fid, sb);
if ( inode ) {
coda_flag_inode(inode, C_VATTR);
......@@ -890,7 +862,6 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
case CODA_PURGEFID : {
struct inode *inode;
ViceFid *fid = &out->coda_purgefid.CodaFid;
clstats(CODA_PURGEFID);
inode = coda_fid_to_inode(fid, sb);
if ( inode ) {
coda_flag_inode_children(inode, C_PURGE);
......@@ -908,7 +879,6 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
struct inode *inode;
ViceFid *oldfid = &out->coda_replace.OldFid;
ViceFid *newfid = &out->coda_replace.NewFid;
clstats(CODA_REPLACE);
inode = coda_fid_to_inode(oldfid, sb);
if ( inode ) {
coda_replace_fid(inode, oldfid, newfid);
......
......@@ -20,13 +20,25 @@ struct coda_inode_info {
struct ViceFid c_fid; /* Coda identifier */
u_short c_flags; /* flags (see below) */
struct list_head c_cilist; /* list of all coda inodes */
struct file *c_container; /* container file for this cnode */
unsigned int c_contcount; /* refcount for container file */
unsigned int c_mapcount; /* nr of times this inode is mapped */
struct coda_cred c_cached_cred; /* credentials of cached perms */
unsigned int c_cached_perm; /* cached access permissions */
struct inode vfs_inode;
};
/*
* coda fs file private data
*/
#define CODA_MAGIC 0xC0DAC0DA
struct coda_file_info {
int cfi_magic; /* magic number */
struct file *cfi_container; /* container file for this cnode */
unsigned int cfi_mapcount; /* nr of times this file is mapped */
struct coda_cred cfi_cred; /* credentials of opener */
};
#define CODA_FTOC(file) ((struct coda_file_info *)((file)->private_data))
/* flags */
#define C_VATTR 0x1 /* Validity of vattr in inode */
#define C_FLUSH 0x2 /* used after a flush */
......
......@@ -21,6 +21,7 @@
#include <linux/wait.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/coda_fs_i.h>
/* operations */
extern struct inode_operations coda_dir_inode_operations;
......@@ -45,7 +46,6 @@ int coda_setattr(struct dentry *, struct iattr *);
int coda_isnullfid(ViceFid *fid);
/* global variables */
extern int coda_access_cache;
extern int coda_fake_statfs;
/* this file: heloers */
......@@ -53,7 +53,6 @@ static __inline__ struct ViceFid *coda_i2f(struct inode *);
static __inline__ char *coda_i2s(struct inode *);
static __inline__ void coda_flag_inode(struct inode *, int flag);
char *coda_f2s(ViceFid *f);
char *coda_f2s2(ViceFid *f);
int coda_isroot(struct inode *i);
int coda_iscontrol(const char *name, size_t length);
......
......@@ -14,7 +14,6 @@
void coda_sysctl_init(void);
void coda_sysctl_clean(void);
void coda_upcall_stats(int opcode, unsigned long jiffies);
#include <linux/sysctl.h>
#include <linux/coda_fs_i.h>
......@@ -23,13 +22,11 @@ void coda_upcall_stats(int opcode, unsigned long jiffies);
/* these four files are presented to show the result of the statistics:
*
* /proc/fs/coda/vfs_stats
* upcall_stats
* cache_inv_stats
*
* these four files are presented to reset the statistics to 0:
*
* /proc/sys/coda/vfs_stats
* upcall_stats
* cache_inv_stats
*/
......@@ -61,13 +58,6 @@ struct coda_vfs_stats
int readlink;
};
struct coda_upcall_stats_entry
{
int count;
unsigned long time_sum;
unsigned long time_squared_sum;
};
/* cache invalidation statistics */
struct coda_cache_inv_stats
{
......@@ -83,31 +73,16 @@ struct coda_cache_inv_stats
/* these global variables hold the actual statistics data */
extern struct coda_vfs_stats coda_vfs_stat;
extern struct coda_cache_inv_stats coda_cache_inv_stat;
extern int coda_upcall_timestamping;
/* reset statistics to 0 */
void reset_coda_vfs_stats( void );
void reset_coda_upcall_stats( void );
void reset_coda_cache_inv_stats( void );
/* some utitlities to make it easier for you to do statistics for time */
void do_time_stats( struct coda_upcall_stats_entry * pentry,
unsigned long jiffy );
/*
double get_time_average( const struct coda_upcall_stats_entry * pentry );
double get_time_std_deviation( const struct coda_upcall_stats_entry * pentry );
*/
unsigned long get_time_average( const struct coda_upcall_stats_entry * pentry );
unsigned long get_time_std_deviation( const struct coda_upcall_stats_entry * pentry );
/* like coda_dointvec, these functions are to be registered in the ctl_table
* data structure for /proc/sys/... files
*/
int do_reset_coda_vfs_stats( ctl_table * table, int write, struct file * filp,
void * buffer, size_t * lenp );
int do_reset_coda_upcall_stats( ctl_table * table, int write,
struct file * filp, void * buffer,
size_t * lenp );
int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
struct file * filp, void * buffer,
size_t * lenp );
......@@ -115,8 +90,6 @@ int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
/* these functions are called to form the content of /proc/fs/coda/... files */
int coda_vfs_stats_get_info( char * buffer, char ** start, off_t offset,
int length);
int coda_upcall_stats_get_info( char * buffer, char ** start, off_t offset,
int length);
int coda_cache_inv_stats_get_info( char * buffer, char ** start, off_t offset,
int length);
......
......@@ -98,27 +98,7 @@ struct upc_req {
/*
* Statistics
*/
struct coda_upcallstats {
int ncalls; /* client requests */
int nbadcalls; /* upcall failures */
int reqs[CODA_NCALLS]; /* count of each request */
} ;
extern struct coda_upcallstats coda_callstats;
extern struct venus_comm coda_comms[];
static inline void clstats(int opcode)
{
coda_callstats.ncalls++;
if ( (0 <= opcode) && (opcode <= CODA_NCALLS) )
coda_callstats.reqs[opcode]++;
else
printk("clstats called with bad opcode %d\n", opcode);
}
static inline void badclstats(void)
{
coda_callstats.nbadcalls++;
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment