}
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 */
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);
}
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;
}
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,
};
/* file operations for directories */
-int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir)
+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)
{
- unsigned int dt;
-
- switch(cdt) {
- case CDT_UNKNOWN: dt = DT_UNKNOWN; break;
- case CDT_FIFO: dt = DT_FIFO; break;
- case CDT_CHR: dt = DT_CHR; break;
- case CDT_DIR: dt = DT_DIR; break;
- case CDT_BLK: dt = DT_BLK; break;
- case CDT_REG: dt = DT_REG; break;
- case CDT_LNK: dt = DT_LNK; break;
- case CDT_SOCK: dt = DT_SOCK; break;
- case CDT_WHT: dt = DT_WHT; break;
- default: dt = DT_UNKNOWN; break;
- }
- return dt;
+ unsigned int dt;
+
+ switch(cdt) {
+ case CDT_UNKNOWN: dt = DT_UNKNOWN; break;
+ case CDT_FIFO: dt = DT_FIFO; break;
+ case CDT_CHR: dt = DT_CHR; break;
+ case CDT_DIR: dt = DT_DIR; break;
+ case CDT_BLK: dt = DT_BLK; break;
+ case CDT_REG: dt = DT_REG; break;
+ case CDT_LNK: dt = DT_LNK; break;
+ case CDT_SOCK: dt = DT_SOCK; break;
+ case CDT_WHT: dt = DT_WHT; break;
+ default: dt = DT_UNKNOWN; break;
+ }
+ return dt;
}
/* 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 =
+ 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);
/* catch truncated reads */
if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
- printk("coda_venus_readdir: short read: %ld\n",
- filp->f_dentry->d_inode->i_ino);
- ret = -EBADF;
- break;
+ printk("coda_venus_readdir: short read: %ld\n",
+ filp->f_dentry->d_inode->i_ino);
+ ret = -EBADF;
+ break;
}
/* 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",
- filp->f_dentry->d_inode->i_ino);
- ret = -EBADF;
- break;
+ 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);
- /* failure means no space for filling in this round */
- if (ret < 0) break;
- result++;
+ 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++;
}
/* we'll always have progress because d_reclen is unsigned and
* we've already established it is non-zero. */
filp->f_pos += vdir->d_reclen;
}
+ }
kfree(vdir);
- return result ? result : ret;
+ return result ? result : ret;
}
/* called when a cache lookup succeeds */
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
/* 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);
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;
}
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;
+ cfi = CODA_FTOC(coda_file);
+ BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
- cflags = coda_flags_to_cflags(flags);
+ coda_inode = coda_file->f_dentry->d_inode;
- inode = file->f_dentry->d_inode;
- cii = ITOC(inode);
- cfile = cii->c_container;
- if (!cfile) BUG();
+ err = venus_store(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
+ &cfi->cfi_cred);
- cinode = cfile->f_dentry->d_inode;
-
- 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;
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();
}
}
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,
};
* Copyright (C) Carnegie Mellon University
*/
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
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;
/* 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)
{
struct coda_inode_info *cii = ITOC(inode);
- if (cii->c_container) BUG();
-
- list_del_init(&cii->c_cilist);
- inode->i_mapping = &inode->i_data;
+ list_del_init(&cii->c_cilist);
coda_cache_clear_inode(inode);
}
int coda_setattr(struct dentry *de, struct iattr *iattr)
{
struct inode *inode = de->d_inode;
- struct coda_vattr vattr;
- int error;
-
+ struct coda_vattr vattr;
+ int error;
+
lock_kernel();
- memset(&vattr, 0, sizeof(vattr));
+ memset(&vattr, 0, sizeof(vattr));
inode->i_ctime = CURRENT_TIME;
- coda_iattr_to_vattr(iattr, &vattr);
- vattr.va_type = C_VNON; /* cannot set type */
+ coda_iattr_to_vattr(iattr, &vattr);
+ vattr.va_type = C_VNON; /* cannot set type */
/* Venus is responsible for truncating the container-file!!! */
error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr);
}
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)
}
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,
};
+
#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>
/* 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 */
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;
}
struct address_space_operations coda_symlink_aops = {
- readpage: coda_symlink_filler
+ .readpage = coda_symlink_filler,
};
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <linux/utsname.h>
-#define __NO_VERSION__
#include <linux/module.h>
#include <linux/coda.h>
#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 */
{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 }
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 )
{
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 )
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)
{
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
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
#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
insize = SIZE(store);
UPARG(CODA_STORE);
- if ( cred ) {
- memcpy(&(inp->ih.cred), cred, sizeof(*cred));
- } else
- printk("CODA: store without valid file creds.\n");
+ memcpy(&(inp->ih.cred), cred, sizeof(*cred));
inp->coda_store.VFid = *fid;
inp->coda_store.flags = 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");
+ memcpy(&(inp->ih.cred), cred, sizeof(*cred));
inp->coda_close.VFid = *fid;
inp->coda_close.flags = flags;
*
*/
-static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp,
- struct venus_comm *vcommp)
+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 )
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;
}
int inSize, int *outSize,
union inputArgs *buffer)
{
- unsigned long runtime;
struct venus_comm *vcommp;
union outputArgs *out;
struct upc_req *req;
* 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... */
exit:
upc_free(req);
- if (error)
- badclstats();
return error;
}
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);
printk("PURGEUSER: null cred!\n");
return 0;
}
- clstats(CODA_PURGEUSER);
coda_cache_clear_all(sb, cred);
return(0);
}
case CODA_ZAPDIR : {
struct inode *inode;
ViceFid *fid = &out->coda_zapdir.CodaFid;
- clstats(CODA_ZAPDIR);
inode = coda_fid_to_inode(fid, sb);
if (inode) {
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);
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);
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);
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 */
#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;
int coda_isnullfid(ViceFid *fid);
/* global variables */
-extern int coda_access_cache;
extern int coda_fake_statfs;
/* this file: heloers */
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);
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>
/* 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
*/
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
{
/* 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 );
/* 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);
/*
* 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