aboutsummaryrefslogtreecommitdiffstats
path: root/fs/coda
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/coda
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'fs/coda')
-rw-r--r--fs/coda/Makefile12
-rw-r--r--fs/coda/cache.c120
-rw-r--r--fs/coda/cnode.c172
-rw-r--r--fs/coda/coda_linux.c197
-rw-r--r--fs/coda/dir.c704
-rw-r--r--fs/coda/file.c300
-rw-r--r--fs/coda/inode.c321
-rw-r--r--fs/coda/pioctl.c95
-rw-r--r--fs/coda/psdev.c462
-rw-r--r--fs/coda/symlink.c55
-rw-r--r--fs/coda/sysctl.c254
-rw-r--r--fs/coda/upcall.c914
12 files changed, 3606 insertions, 0 deletions
diff --git a/fs/coda/Makefile b/fs/coda/Makefile
new file mode 100644
index 000000000000..6c22e61da397
--- /dev/null
+++ b/fs/coda/Makefile
@@ -0,0 +1,12 @@
1#
2# Makefile for the Linux Coda filesystem routines.
3#
4
5obj-$(CONFIG_CODA_FS) += coda.o
6
7coda-objs := psdev.o cache.o cnode.o inode.o dir.o file.o upcall.o \
8 coda_linux.o symlink.o pioctl.o sysctl.o
9
10# If you want debugging output, please uncomment the following line.
11
12# EXTRA_CFLAGS += -DDEBUG -DDEBUG_SMB_MALLOC=1
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
new file mode 100644
index 000000000000..80072fd9b7fa
--- /dev/null
+++ b/fs/coda/cache.c
@@ -0,0 +1,120 @@
1/*
2 * Cache operations for Coda.
3 * For Linux 2.1: (C) 1997 Carnegie Mellon University
4 * For Linux 2.3: (C) 2000 Carnegie Mellon University
5 *
6 * Carnegie Mellon encourages users of this code to contribute improvements
7 * to the Coda project http://www.coda.cs.cmu.edu/ <coda@cs.cmu.edu>.
8 */
9
10#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/time.h>
13#include <linux/fs.h>
14#include <linux/stat.h>
15#include <linux/errno.h>
16#include <asm/uaccess.h>
17#include <linux/string.h>
18#include <linux/list.h>
19
20#include <linux/coda.h>
21#include <linux/coda_linux.h>
22#include <linux/coda_psdev.h>
23#include <linux/coda_fs_i.h>
24#include <linux/coda_cache.h>
25
26static atomic_t permission_epoch = ATOMIC_INIT(0);
27
28/* replace or extend an acl cache hit */
29void coda_cache_enter(struct inode *inode, int mask)
30{
31 struct coda_inode_info *cii = ITOC(inode);
32
33 cii->c_cached_epoch = atomic_read(&permission_epoch);
34 if (cii->c_uid != current->fsuid) {
35 cii->c_uid = current->fsuid;
36 cii->c_cached_perm = mask;
37 } else
38 cii->c_cached_perm |= mask;
39}
40
41/* remove cached acl from an inode */
42void coda_cache_clear_inode(struct inode *inode)
43{
44 struct coda_inode_info *cii = ITOC(inode);
45 cii->c_cached_perm = 0;
46}
47
48/* remove all acl caches */
49void coda_cache_clear_all(struct super_block *sb)
50{
51 struct coda_sb_info *sbi;
52
53 sbi = coda_sbp(sb);
54 if (!sbi) BUG();
55
56 atomic_inc(&permission_epoch);
57}
58
59
60/* check if the mask has been matched against the acl already */
61int coda_cache_check(struct inode *inode, int mask)
62{
63 struct coda_inode_info *cii = ITOC(inode);
64 int hit;
65
66 hit = (mask & cii->c_cached_perm) == mask &&
67 cii->c_uid == current->fsuid &&
68 cii->c_cached_epoch == atomic_read(&permission_epoch);
69
70 return hit;
71}
72
73
74/* Purging dentries and children */
75/* The following routines drop dentries which are not
76 in use and flag dentries which are in use to be
77 zapped later.
78
79 The flags are detected by:
80 - coda_dentry_revalidate (for lookups) if the flag is C_PURGE
81 - coda_dentry_delete: to remove dentry from the cache when d_count
82 falls to zero
83 - an inode method coda_revalidate (for attributes) if the
84 flag is C_VATTR
85*/
86
87/* this won't do any harm: just flag all children */
88static void coda_flag_children(struct dentry *parent, int flag)
89{
90 struct list_head *child;
91 struct dentry *de;
92
93 spin_lock(&dcache_lock);
94 list_for_each(child, &parent->d_subdirs)
95 {
96 de = list_entry(child, struct dentry, d_child);
97 /* don't know what to do with negative dentries */
98 if ( ! de->d_inode )
99 continue;
100 coda_flag_inode(de->d_inode, flag);
101 }
102 spin_unlock(&dcache_lock);
103 return;
104}
105
106void coda_flag_inode_children(struct inode *inode, int flag)
107{
108 struct dentry *alias_de;
109
110 if ( !inode || !S_ISDIR(inode->i_mode))
111 return;
112
113 alias_de = d_find_alias(inode);
114 if (!alias_de)
115 return;
116 coda_flag_children(alias_de, flag);
117 shrink_dcache_parent(alias_de);
118 dput(alias_de);
119}
120
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
new file mode 100644
index 000000000000..23aeef5aa814
--- /dev/null
+++ b/fs/coda/cnode.c
@@ -0,0 +1,172 @@
1/* cnode related routines for the coda kernel code
2 (C) 1996 Peter Braam
3 */
4
5#include <linux/types.h>
6#include <linux/string.h>
7#include <linux/time.h>
8
9#include <linux/coda.h>
10#include <linux/coda_linux.h>
11#include <linux/coda_fs_i.h>
12#include <linux/coda_psdev.h>
13
14static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2)
15{
16 return memcmp(fid1, fid2, sizeof(*fid1)) == 0;
17}
18
19static struct inode_operations coda_symlink_inode_operations = {
20 .readlink = generic_readlink,
21 .follow_link = page_follow_link_light,
22 .put_link = page_put_link,
23 .setattr = coda_setattr,
24};
25
26/* cnode.c */
27static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
28{
29 coda_vattr_to_iattr(inode, attr);
30
31 if (S_ISREG(inode->i_mode)) {
32 inode->i_op = &coda_file_inode_operations;
33 inode->i_fop = &coda_file_operations;
34 } else if (S_ISDIR(inode->i_mode)) {
35 inode->i_op = &coda_dir_inode_operations;
36 inode->i_fop = &coda_dir_operations;
37 } else if (S_ISLNK(inode->i_mode)) {
38 inode->i_op = &coda_symlink_inode_operations;
39 inode->i_data.a_ops = &coda_symlink_aops;
40 inode->i_mapping = &inode->i_data;
41 } else
42 init_special_inode(inode, inode->i_mode, huge_decode_dev(attr->va_rdev));
43}
44
45static int coda_test_inode(struct inode *inode, void *data)
46{
47 struct CodaFid *fid = (struct CodaFid *)data;
48 return coda_fideq(&(ITOC(inode)->c_fid), fid);
49}
50
51static int coda_set_inode(struct inode *inode, void *data)
52{
53 struct CodaFid *fid = (struct CodaFid *)data;
54 ITOC(inode)->c_fid = *fid;
55 return 0;
56}
57
58static int coda_fail_inode(struct inode *inode, void *data)
59{
60 return -1;
61}
62
63struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
64 struct coda_vattr * attr)
65{
66 struct inode *inode;
67 struct coda_inode_info *cii;
68 unsigned long hash = coda_f2i(fid);
69
70 inode = iget5_locked(sb, hash, coda_test_inode, coda_set_inode, fid);
71
72 if (!inode)
73 return ERR_PTR(-ENOMEM);
74
75 if (inode->i_state & I_NEW) {
76 cii = ITOC(inode);
77 /* we still need to set i_ino for things like stat(2) */
78 inode->i_ino = hash;
79 cii->c_mapcount = 0;
80 unlock_new_inode(inode);
81 }
82
83 /* always replace the attributes, type might have changed */
84 coda_fill_inode(inode, attr);
85 return inode;
86}
87
88/* this is effectively coda_iget:
89 - get attributes (might be cached)
90 - get the inode for the fid using vfs iget
91 - link the two up if this is needed
92 - fill in the attributes
93*/
94int coda_cnode_make(struct inode **inode, struct CodaFid *fid, struct super_block *sb)
95{
96 struct coda_vattr attr;
97 int error;
98
99 /* We get inode numbers from Venus -- see venus source */
100 error = venus_getattr(sb, fid, &attr);
101 if ( error ) {
102 *inode = NULL;
103 return error;
104 }
105
106 *inode = coda_iget(sb, fid, &attr);
107 if ( IS_ERR(*inode) ) {
108 printk("coda_cnode_make: coda_iget failed\n");
109 return PTR_ERR(*inode);
110 }
111 return 0;
112}
113
114
115void coda_replace_fid(struct inode *inode, struct CodaFid *oldfid,
116 struct CodaFid *newfid)
117{
118 struct coda_inode_info *cii;
119 unsigned long hash = coda_f2i(newfid);
120
121 cii = ITOC(inode);
122
123 if (!coda_fideq(&cii->c_fid, oldfid))
124 BUG();
125
126 /* replace fid and rehash inode */
127 /* XXX we probably need to hold some lock here! */
128 remove_inode_hash(inode);
129 cii->c_fid = *newfid;
130 inode->i_ino = hash;
131 __insert_inode_hash(inode, hash);
132}
133
134/* convert a fid to an inode. */
135struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
136{
137 struct inode *inode;
138 unsigned long hash = coda_f2i(fid);
139
140 if ( !sb ) {
141 printk("coda_fid_to_inode: no sb!\n");
142 return NULL;
143 }
144
145 inode = iget5_locked(sb, hash, coda_test_inode, coda_fail_inode, fid);
146 if ( !inode )
147 return NULL;
148
149 /* we should never see newly created inodes because we intentionally
150 * fail in the initialization callback */
151 BUG_ON(inode->i_state & I_NEW);
152
153 return inode;
154}
155
156/* the CONTROL inode is made without asking attributes from Venus */
157int coda_cnode_makectl(struct inode **inode, struct super_block *sb)
158{
159 int error = -ENOMEM;
160
161 *inode = new_inode(sb);
162 if (*inode) {
163 (*inode)->i_ino = CTL_INO;
164 (*inode)->i_op = &coda_ioctl_inode_operations;
165 (*inode)->i_fop = &coda_ioctl_operations;
166 (*inode)->i_mode = 0444;
167 error = 0;
168 }
169
170 return error;
171}
172
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
new file mode 100644
index 000000000000..5597080cb811
--- /dev/null
+++ b/fs/coda/coda_linux.c
@@ -0,0 +1,197 @@
1/*
2 * Inode operations for Coda filesystem
3 * Original version: (C) 1996 P. Braam and M. Callahan
4 * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
5 *
6 * Carnegie Mellon encourages users to contribute improvements to
7 * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
8 */
9
10#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/time.h>
13#include <linux/fs.h>
14#include <linux/stat.h>
15#include <linux/errno.h>
16#include <asm/uaccess.h>
17#include <linux/string.h>
18
19#include <linux/coda.h>
20#include <linux/coda_linux.h>
21#include <linux/coda_psdev.h>
22#include <linux/coda_fs_i.h>
23
24/* initialize the debugging variables */
25int coda_fake_statfs;
26
27/* print a fid */
28char * coda_f2s(struct CodaFid *f)
29{
30 static char s[60];
31#ifdef CONFIG_CODA_FS_OLD_API
32 sprintf(s, "(%08x.%08x.%08x)", f->opaque[0], f->opaque[1], f->opaque[2]);
33#else
34 sprintf(s, "(%08x.%08x.%08x.%08x)", f->opaque[0], f->opaque[1], f->opaque[2], f->opaque[3]);
35#endif
36 return s;
37}
38
39/* recognize special .CONTROL name */
40int coda_iscontrol(const char *name, size_t length)
41{
42 return ((CODA_CONTROLLEN == length) &&
43 (strncmp(name, CODA_CONTROL, CODA_CONTROLLEN) == 0));
44}
45
46/* recognize /coda inode */
47int coda_isroot(struct inode *i)
48{
49 return ( i->i_sb->s_root->d_inode == i );
50}
51
52unsigned short coda_flags_to_cflags(unsigned short flags)
53{
54 unsigned short coda_flags = 0;
55
56 if ((flags & O_ACCMODE) == O_RDONLY)
57 coda_flags |= C_O_READ;
58
59 if ((flags & O_ACCMODE) == O_RDWR)
60 coda_flags |= C_O_READ | C_O_WRITE;
61
62 if ((flags & O_ACCMODE) == O_WRONLY)
63 coda_flags |= C_O_WRITE;
64
65 if (flags & O_TRUNC)
66 coda_flags |= C_O_TRUNC;
67
68 if (flags & O_CREAT)
69 coda_flags |= C_O_CREAT;
70
71 if (flags & O_EXCL)
72 coda_flags |= C_O_EXCL;
73
74 return coda_flags;
75}
76
77
78/* utility functions below */
79void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
80{
81 int inode_type;
82 /* inode's i_flags, i_ino are set by iget
83 XXX: is this all we need ??
84 */
85 switch (attr->va_type) {
86 case C_VNON:
87 inode_type = 0;
88 break;
89 case C_VREG:
90 inode_type = S_IFREG;
91 break;
92 case C_VDIR:
93 inode_type = S_IFDIR;
94 break;
95 case C_VLNK:
96 inode_type = S_IFLNK;
97 break;
98 default:
99 inode_type = 0;
100 }
101 inode->i_mode |= inode_type;
102
103 if (attr->va_mode != (u_short) -1)
104 inode->i_mode = attr->va_mode | inode_type;
105 if (attr->va_uid != -1)
106 inode->i_uid = (uid_t) attr->va_uid;
107 if (attr->va_gid != -1)
108 inode->i_gid = (gid_t) attr->va_gid;
109 if (attr->va_nlink != -1)
110 inode->i_nlink = attr->va_nlink;
111 if (attr->va_size != -1)
112 inode->i_size = attr->va_size;
113 if (attr->va_blocksize != -1)
114 inode->i_blksize = attr->va_blocksize;
115 if (attr->va_size != -1)
116 inode->i_blocks = (attr->va_size + 511) >> 9;
117 if (attr->va_atime.tv_sec != -1)
118 inode->i_atime = attr->va_atime;
119 if (attr->va_mtime.tv_sec != -1)
120 inode->i_mtime = attr->va_mtime;
121 if (attr->va_ctime.tv_sec != -1)
122 inode->i_ctime = attr->va_ctime;
123}
124
125
126/*
127 * BSD sets attributes that need not be modified to -1.
128 * Linux uses the valid field to indicate what should be
129 * looked at. The BSD type field needs to be deduced from linux
130 * mode.
131 * So we have to do some translations here.
132 */
133
134void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr)
135{
136 unsigned int valid;
137
138 /* clean out */
139 vattr->va_mode = (umode_t) -1;
140 vattr->va_uid = (vuid_t) -1;
141 vattr->va_gid = (vgid_t) -1;
142 vattr->va_size = (off_t) -1;
143 vattr->va_atime.tv_sec = (time_t) -1;
144 vattr->va_atime.tv_nsec = (time_t) -1;
145 vattr->va_mtime.tv_sec = (time_t) -1;
146 vattr->va_mtime.tv_nsec = (time_t) -1;
147 vattr->va_ctime.tv_sec = (time_t) -1;
148 vattr->va_ctime.tv_nsec = (time_t) -1;
149 vattr->va_type = C_VNON;
150 vattr->va_fileid = -1;
151 vattr->va_gen = -1;
152 vattr->va_bytes = -1;
153 vattr->va_nlink = -1;
154 vattr->va_blocksize = -1;
155 vattr->va_rdev = -1;
156 vattr->va_flags = 0;
157
158 /* determine the type */
159#if 0
160 mode = iattr->ia_mode;
161 if ( S_ISDIR(mode) ) {
162 vattr->va_type = C_VDIR;
163 } else if ( S_ISREG(mode) ) {
164 vattr->va_type = C_VREG;
165 } else if ( S_ISLNK(mode) ) {
166 vattr->va_type = C_VLNK;
167 } else {
168 /* don't do others */
169 vattr->va_type = C_VNON;
170 }
171#endif
172
173 /* set those vattrs that need change */
174 valid = iattr->ia_valid;
175 if ( valid & ATTR_MODE ) {
176 vattr->va_mode = iattr->ia_mode;
177 }
178 if ( valid & ATTR_UID ) {
179 vattr->va_uid = (vuid_t) iattr->ia_uid;
180 }
181 if ( valid & ATTR_GID ) {
182 vattr->va_gid = (vgid_t) iattr->ia_gid;
183 }
184 if ( valid & ATTR_SIZE ) {
185 vattr->va_size = iattr->ia_size;
186 }
187 if ( valid & ATTR_ATIME ) {
188 vattr->va_atime = iattr->ia_atime;
189 }
190 if ( valid & ATTR_MTIME ) {
191 vattr->va_mtime = iattr->ia_mtime;
192 }
193 if ( valid & ATTR_CTIME ) {
194 vattr->va_ctime = iattr->ia_ctime;
195 }
196}
197
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
new file mode 100644
index 000000000000..2391766e9c7c
--- /dev/null
+++ b/fs/coda/dir.c
@@ -0,0 +1,704 @@
1
2/*
3 * Directory operations for Coda filesystem
4 * Original version: (C) 1996 P. Braam and M. Callahan
5 * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
6 *
7 * Carnegie Mellon encourages users to contribute improvements to
8 * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
9 */
10
11#include <linux/types.h>
12#include <linux/kernel.h>
13#include <linux/time.h>
14#include <linux/fs.h>
15#include <linux/file.h>
16#include <linux/stat.h>
17#include <linux/errno.h>
18#include <linux/string.h>
19#include <linux/smp_lock.h>
20
21#include <asm/uaccess.h>
22
23#include <linux/coda.h>
24#include <linux/coda_linux.h>
25#include <linux/coda_psdev.h>
26#include <linux/coda_fs_i.h>
27#include <linux/coda_cache.h>
28#include <linux/coda_proc.h>
29
30/* dir inode-ops */
31static int coda_create(struct inode *dir, struct dentry *new, int mode, struct nameidata *nd);
32static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, struct nameidata *nd);
33static int coda_link(struct dentry *old_dentry, struct inode *dir_inode,
34 struct dentry *entry);
35static int coda_unlink(struct inode *dir_inode, struct dentry *entry);
36static int coda_symlink(struct inode *dir_inode, struct dentry *entry,
37 const char *symname);
38static int coda_mkdir(struct inode *dir_inode, struct dentry *entry, int mode);
39static int coda_rmdir(struct inode *dir_inode, struct dentry *entry);
40static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
41 struct inode *new_inode, struct dentry *new_dentry);
42
43/* dir file-ops */
44static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
45
46/* dentry ops */
47static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd);
48static int coda_dentry_delete(struct dentry *);
49
50/* support routines */
51static int coda_venus_readdir(struct file *filp, filldir_t filldir,
52 void *dirent, struct dentry *dir);
53int coda_fsync(struct file *, struct dentry *dentry, int datasync);
54
55/* same as fs/bad_inode.c */
56static int coda_return_EIO(void)
57{
58 return -EIO;
59}
60#define CODA_EIO_ERROR ((void *) (coda_return_EIO))
61
62static struct dentry_operations coda_dentry_operations =
63{
64 .d_revalidate = coda_dentry_revalidate,
65 .d_delete = coda_dentry_delete,
66};
67
68struct inode_operations coda_dir_inode_operations =
69{
70 .create = coda_create,
71 .lookup = coda_lookup,
72 .link = coda_link,
73 .unlink = coda_unlink,
74 .symlink = coda_symlink,
75 .mkdir = coda_mkdir,
76 .rmdir = coda_rmdir,
77 .mknod = CODA_EIO_ERROR,
78 .rename = coda_rename,
79 .permission = coda_permission,
80 .getattr = coda_getattr,
81 .setattr = coda_setattr,
82};
83
84struct file_operations coda_dir_operations = {
85 .llseek = generic_file_llseek,
86 .read = generic_read_dir,
87 .readdir = coda_readdir,
88 .open = coda_open,
89 .flush = coda_flush,
90 .release = coda_release,
91 .fsync = coda_fsync,
92};
93
94
95/* inode operations for directories */
96/* access routines: lookup, readlink, permission */
97static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd)
98{
99 struct inode *res_inode = NULL;
100 struct CodaFid resfid = { { 0, } };
101 int dropme = 0; /* to indicate entry should not be cached */
102 int type = 0;
103 int error = 0;
104 const char *name = entry->d_name.name;
105 size_t length = entry->d_name.len;
106
107 if ( length > CODA_MAXNAMLEN ) {
108 printk("name too long: lookup, %s (%*s)\n",
109 coda_i2s(dir), (int)length, name);
110 return ERR_PTR(-ENAMETOOLONG);
111 }
112
113 lock_kernel();
114 /* control object, create inode on the fly */
115 if (coda_isroot(dir) && coda_iscontrol(name, length)) {
116 error = coda_cnode_makectl(&res_inode, dir->i_sb);
117 dropme = 1;
118 goto exit;
119 }
120
121 error = venus_lookup(dir->i_sb, coda_i2f(dir),
122 (const char *)name, length, &type, &resfid);
123
124 res_inode = NULL;
125 if (!error) {
126 if (type & CODA_NOCACHE) {
127 type &= (~CODA_NOCACHE);
128 dropme = 1;
129 }
130
131 error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
132 if (error) {
133 unlock_kernel();
134 return ERR_PTR(error);
135 }
136 } else if (error != -ENOENT) {
137 unlock_kernel();
138 return ERR_PTR(error);
139 }
140
141exit:
142 entry->d_time = 0;
143 entry->d_op = &coda_dentry_operations;
144 d_add(entry, res_inode);
145 if ( dropme ) {
146 d_drop(entry);
147 coda_flag_inode(res_inode, C_VATTR);
148 }
149 unlock_kernel();
150 return NULL;
151}
152
153
154int coda_permission(struct inode *inode, int mask, struct nameidata *nd)
155{
156 int error = 0;
157
158 if (!mask)
159 return 0;
160
161 lock_kernel();
162
163 coda_vfs_stat.permission++;
164
165 if (coda_cache_check(inode, mask))
166 goto out;
167
168 error = venus_access(inode->i_sb, coda_i2f(inode), mask);
169
170 if (!error)
171 coda_cache_enter(inode, mask);
172
173 out:
174 unlock_kernel();
175
176 return error;
177}
178
179
180static inline void coda_dir_changed(struct inode *dir, int link)
181{
182#ifdef REQUERY_VENUS_FOR_MTIME
183 /* invalidate the directory cnode's attributes so we refetch the
184 * attributes from venus next time the inode is referenced */
185 coda_flag_inode(dir, C_VATTR);
186#else
187 /* optimistically we can also act as if our nose bleeds. The
188 * granularity of the mtime is coarse anyways so we might actually be
189 * right most of the time. Note: we only do this for directories. */
190 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
191#endif
192 if (link)
193 dir->i_nlink += link;
194}
195
196/* creation routines: create, mknod, mkdir, link, symlink */
197static int coda_create(struct inode *dir, struct dentry *de, int mode, struct nameidata *nd)
198{
199 int error=0;
200 const char *name=de->d_name.name;
201 int length=de->d_name.len;
202 struct inode *inode;
203 struct CodaFid newfid;
204 struct coda_vattr attrs;
205
206 lock_kernel();
207 coda_vfs_stat.create++;
208
209 if (coda_isroot(dir) && coda_iscontrol(name, length)) {
210 unlock_kernel();
211 return -EPERM;
212 }
213
214 error = venus_create(dir->i_sb, coda_i2f(dir), name, length,
215 0, mode, &newfid, &attrs);
216
217 if ( error ) {
218 unlock_kernel();
219 d_drop(de);
220 return error;
221 }
222
223 inode = coda_iget(dir->i_sb, &newfid, &attrs);
224 if ( IS_ERR(inode) ) {
225 unlock_kernel();
226 d_drop(de);
227 return PTR_ERR(inode);
228 }
229
230 /* invalidate the directory cnode's attributes */
231 coda_dir_changed(dir, 0);
232 unlock_kernel();
233 d_instantiate(de, inode);
234 return 0;
235}
236
237static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
238{
239 struct inode *inode;
240 struct coda_vattr attrs;
241 const char *name = de->d_name.name;
242 int len = de->d_name.len;
243 int error;
244 struct CodaFid newfid;
245
246 lock_kernel();
247 coda_vfs_stat.mkdir++;
248
249 if (coda_isroot(dir) && coda_iscontrol(name, len)) {
250 unlock_kernel();
251 return -EPERM;
252 }
253
254 attrs.va_mode = mode;
255 error = venus_mkdir(dir->i_sb, coda_i2f(dir),
256 name, len, &newfid, &attrs);
257
258 if ( error ) {
259 unlock_kernel();
260 d_drop(de);
261 return error;
262 }
263
264 inode = coda_iget(dir->i_sb, &newfid, &attrs);
265 if ( IS_ERR(inode) ) {
266 unlock_kernel();
267 d_drop(de);
268 return PTR_ERR(inode);
269 }
270
271 /* invalidate the directory cnode's attributes */
272 coda_dir_changed(dir, 1);
273 unlock_kernel();
274 d_instantiate(de, inode);
275 return 0;
276}
277
278/* try to make de an entry in dir_inodde linked to source_de */
279static int coda_link(struct dentry *source_de, struct inode *dir_inode,
280 struct dentry *de)
281{
282 struct inode *inode = source_de->d_inode;
283 const char * name = de->d_name.name;
284 int len = de->d_name.len;
285 int error;
286
287 lock_kernel();
288 coda_vfs_stat.link++;
289
290 if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
291 unlock_kernel();
292 return -EPERM;
293 }
294
295 error = venus_link(dir_inode->i_sb, coda_i2f(inode),
296 coda_i2f(dir_inode), (const char *)name, len);
297
298 if (error) {
299 d_drop(de);
300 goto out;
301 }
302
303 coda_dir_changed(dir_inode, 0);
304 atomic_inc(&inode->i_count);
305 d_instantiate(de, inode);
306 inode->i_nlink++;
307
308out:
309 unlock_kernel();
310 return(error);
311}
312
313
314static int coda_symlink(struct inode *dir_inode, struct dentry *de,
315 const char *symname)
316{
317 const char *name = de->d_name.name;
318 int len = de->d_name.len;
319 int symlen;
320 int error=0;
321
322 lock_kernel();
323 coda_vfs_stat.symlink++;
324
325 if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
326 unlock_kernel();
327 return -EPERM;
328 }
329
330 symlen = strlen(symname);
331 if ( symlen > CODA_MAXPATHLEN ) {
332 unlock_kernel();
333 return -ENAMETOOLONG;
334 }
335
336 /*
337 * This entry is now negative. Since we do not create
338 * an inode for the entry we have to drop it.
339 */
340 d_drop(de);
341 error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len,
342 symname, symlen);
343
344 /* mtime is no good anymore */
345 if ( !error )
346 coda_dir_changed(dir_inode, 0);
347
348 unlock_kernel();
349 return error;
350}
351
352/* destruction routines: unlink, rmdir */
353int coda_unlink(struct inode *dir, struct dentry *de)
354{
355 int error;
356 const char *name = de->d_name.name;
357 int len = de->d_name.len;
358
359 lock_kernel();
360 coda_vfs_stat.unlink++;
361
362 error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
363 if ( error ) {
364 unlock_kernel();
365 return error;
366 }
367
368 coda_dir_changed(dir, 0);
369 de->d_inode->i_nlink--;
370 unlock_kernel();
371
372 return 0;
373}
374
375int coda_rmdir(struct inode *dir, struct dentry *de)
376{
377 const char *name = de->d_name.name;
378 int len = de->d_name.len;
379 int error;
380
381 lock_kernel();
382 coda_vfs_stat.rmdir++;
383
384 if (!d_unhashed(de)) {
385 unlock_kernel();
386 return -EBUSY;
387 }
388 error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
389
390 if ( error ) {
391 unlock_kernel();
392 return error;
393 }
394
395 coda_dir_changed(dir, -1);
396 de->d_inode->i_nlink--;
397 d_delete(de);
398 unlock_kernel();
399
400 return 0;
401}
402
403/* rename */
404static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
405 struct inode *new_dir, struct dentry *new_dentry)
406{
407 const char *old_name = old_dentry->d_name.name;
408 const char *new_name = new_dentry->d_name.name;
409 int old_length = old_dentry->d_name.len;
410 int new_length = new_dentry->d_name.len;
411 int link_adjust = 0;
412 int error;
413
414 lock_kernel();
415 coda_vfs_stat.rename++;
416
417 error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
418 coda_i2f(new_dir), old_length, new_length,
419 (const char *) old_name, (const char *)new_name);
420
421 if ( !error ) {
422 if ( new_dentry->d_inode ) {
423 if ( S_ISDIR(new_dentry->d_inode->i_mode) )
424 link_adjust = 1;
425
426 coda_dir_changed(old_dir, -link_adjust);
427 coda_dir_changed(new_dir, link_adjust);
428 coda_flag_inode(new_dentry->d_inode, C_VATTR);
429 } else {
430 coda_flag_inode(old_dir, C_VATTR);
431 coda_flag_inode(new_dir, C_VATTR);
432 }
433 }
434 unlock_kernel();
435
436 return error;
437}
438
439
440/* file operations for directories */
441int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir)
442{
443 struct dentry *coda_dentry = coda_file->f_dentry;
444 struct coda_file_info *cfi;
445 struct file *host_file;
446 struct inode *host_inode;
447 int ret;
448
449 cfi = CODA_FTOC(coda_file);
450 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
451 host_file = cfi->cfi_container;
452
453 coda_vfs_stat.readdir++;
454
455 host_inode = host_file->f_dentry->d_inode;
456 down(&host_inode->i_sem);
457 host_file->f_pos = coda_file->f_pos;
458
459 if (!host_file->f_op->readdir) {
460 /* Venus: we must read Venus dirents from the file */
461 ret = coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
462 } else {
463 /* potemkin case: we were handed a directory inode. */
464 /* Yuk, we can't call vfs_readdir because we are already
465 * holding the inode semaphore. */
466 ret = -ENOTDIR;
467 if (!host_file->f_op || !host_file->f_op->readdir)
468 goto out;
469
470 ret = -ENOENT;
471 if (!IS_DEADDIR(host_inode)) {
472 ret = host_file->f_op->readdir(host_file, filldir, dirent);
473 file_accessed(host_file);
474 }
475 }
476out:
477 coda_file->f_pos = host_file->f_pos;
478 up(&host_inode->i_sem);
479
480 return ret;
481}
482
483static inline unsigned int CDT2DT(unsigned char cdt)
484{
485 unsigned int dt;
486
487 switch(cdt) {
488 case CDT_UNKNOWN: dt = DT_UNKNOWN; break;
489 case CDT_FIFO: dt = DT_FIFO; break;
490 case CDT_CHR: dt = DT_CHR; break;
491 case CDT_DIR: dt = DT_DIR; break;
492 case CDT_BLK: dt = DT_BLK; break;
493 case CDT_REG: dt = DT_REG; break;
494 case CDT_LNK: dt = DT_LNK; break;
495 case CDT_SOCK: dt = DT_SOCK; break;
496 case CDT_WHT: dt = DT_WHT; break;
497 default: dt = DT_UNKNOWN; break;
498 }
499 return dt;
500}
501
502/* support routines */
503static int coda_venus_readdir(struct file *filp, filldir_t filldir,
504 void *dirent, struct dentry *dir)
505{
506 int result = 0; /* # of entries returned */
507 struct venus_dirent *vdir;
508 unsigned long vdir_size =
509 (unsigned long)(&((struct venus_dirent *)0)->d_name);
510 unsigned int type;
511 struct qstr name;
512 ino_t ino;
513 int ret, i;
514
515 vdir = (struct venus_dirent *)kmalloc(sizeof(*vdir), GFP_KERNEL);
516 if (!vdir) return -ENOMEM;
517
518 i = filp->f_pos;
519 switch(i) {
520 case 0:
521 ret = filldir(dirent, ".", 1, 0, dir->d_inode->i_ino, DT_DIR);
522 if (ret < 0) break;
523 result++;
524 filp->f_pos++;
525 /* fallthrough */
526 case 1:
527 ret = filldir(dirent, "..", 2, 1, dir->d_parent->d_inode->i_ino, DT_DIR);
528 if (ret < 0) break;
529 result++;
530 filp->f_pos++;
531 /* fallthrough */
532 default:
533 while (1) {
534 /* read entries from the directory file */
535 ret = kernel_read(filp, filp->f_pos - 2, (char *)vdir,
536 sizeof(*vdir));
537 if (ret < 0) {
538 printk("coda_venus_readdir: read dir failed %d\n", ret);
539 break;
540 }
541 if (ret == 0) break; /* end of directory file reached */
542
543 /* catch truncated reads */
544 if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
545 printk("coda_venus_readdir: short read: %ld\n",
546 filp->f_dentry->d_inode->i_ino);
547 ret = -EBADF;
548 break;
549 }
550 /* validate whether the directory file actually makes sense */
551 if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
552 printk("coda_venus_readdir: Invalid dir: %ld\n",
553 filp->f_dentry->d_inode->i_ino);
554 ret = -EBADF;
555 break;
556 }
557
558 name.len = vdir->d_namlen;
559 name.name = vdir->d_name;
560
561 /* Make sure we skip '.' and '..', we already got those */
562 if (name.name[0] == '.' && (name.len == 1 ||
563 (vdir->d_name[1] == '.' && name.len == 2)))
564 vdir->d_fileno = name.len = 0;
565
566 /* skip null entries */
567 if (vdir->d_fileno && name.len) {
568 /* try to look up this entry in the dcache, that way
569 * userspace doesn't have to worry about breaking
570 * getcwd by having mismatched inode numbers for
571 * internal volume mountpoints. */
572 ino = find_inode_number(dir, &name);
573 if (!ino) ino = vdir->d_fileno;
574
575 type = CDT2DT(vdir->d_type);
576 ret = filldir(dirent, name.name, name.len, filp->f_pos,
577 ino, type);
578 /* failure means no space for filling in this round */
579 if (ret < 0) break;
580 result++;
581 }
582 /* we'll always have progress because d_reclen is unsigned and
583 * we've already established it is non-zero. */
584 filp->f_pos += vdir->d_reclen;
585 }
586 }
587 kfree(vdir);
588 return result ? result : ret;
589}
590
591/* called when a cache lookup succeeds */
592static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
593{
594 struct inode *inode = de->d_inode;
595 struct coda_inode_info *cii;
596
597 if (!inode)
598 return 1;
599 lock_kernel();
600 if (coda_isroot(inode))
601 goto out;
602 if (is_bad_inode(inode))
603 goto bad;
604
605 cii = ITOC(de->d_inode);
606 if (!(cii->c_flags & (C_PURGE | C_FLUSH)))
607 goto out;
608
609 shrink_dcache_parent(de);
610
611 /* propagate for a flush */
612 if (cii->c_flags & C_FLUSH)
613 coda_flag_inode_children(inode, C_FLUSH);
614
615 if (atomic_read(&de->d_count) > 1)
616 /* pretend it's valid, but don't change the flags */
617 goto out;
618
619 /* clear the flags. */
620 cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
621
622bad:
623 unlock_kernel();
624 return 0;
625out:
626 unlock_kernel();
627 return 1;
628}
629
630/*
631 * This is the callback from dput() when d_count is going to 0.
632 * We use this to unhash dentries with bad inodes.
633 */
634static int coda_dentry_delete(struct dentry * dentry)
635{
636 int flags;
637
638 if (!dentry->d_inode)
639 return 0;
640
641 flags = (ITOC(dentry->d_inode)->c_flags) & C_PURGE;
642 if (is_bad_inode(dentry->d_inode) || flags) {
643 return 1;
644 }
645 return 0;
646}
647
648
649
650/*
651 * This is called when we want to check if the inode has
652 * changed on the server. Coda makes this easy since the
653 * cache manager Venus issues a downcall to the kernel when this
654 * happens
655 */
656int coda_revalidate_inode(struct dentry *dentry)
657{
658 struct coda_vattr attr;
659 int error = 0;
660 int old_mode;
661 ino_t old_ino;
662 struct inode *inode = dentry->d_inode;
663 struct coda_inode_info *cii = ITOC(inode);
664
665 lock_kernel();
666 if ( !cii->c_flags )
667 goto ok;
668
669 if (cii->c_flags & (C_VATTR | C_PURGE | C_FLUSH)) {
670 error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr);
671 if ( error )
672 goto return_bad;
673
674 /* this inode may be lost if:
675 - it's ino changed
676 - type changes must be permitted for repair and
677 missing mount points.
678 */
679 old_mode = inode->i_mode;
680 old_ino = inode->i_ino;
681 coda_vattr_to_iattr(inode, &attr);
682
683 if ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT)) {
684 printk("Coda: inode %ld, fid %s changed type!\n",
685 inode->i_ino, coda_f2s(&(cii->c_fid)));
686 }
687
688 /* the following can happen when a local fid is replaced
689 with a global one, here we lose and declare the inode bad */
690 if (inode->i_ino != old_ino)
691 goto return_bad;
692
693 coda_flag_inode_children(inode, C_FLUSH);
694 cii->c_flags &= ~(C_VATTR | C_PURGE | C_FLUSH);
695 }
696
697ok:
698 unlock_kernel();
699 return 0;
700
701return_bad:
702 unlock_kernel();
703 return -EIO;
704}
diff --git a/fs/coda/file.c b/fs/coda/file.c
new file mode 100644
index 000000000000..e6bc022568f3
--- /dev/null
+++ b/fs/coda/file.c
@@ -0,0 +1,300 @@
1/*
2 * File operations for Coda.
3 * Original version: (C) 1996 Peter Braam
4 * Rewritten for Linux 2.1: (C) 1997 Carnegie Mellon University
5 *
6 * Carnegie Mellon encourages users of this code to contribute improvements
7 * to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
8 */
9
10#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/time.h>
13#include <linux/file.h>
14#include <linux/fs.h>
15#include <linux/stat.h>
16#include <linux/errno.h>
17#include <linux/smp_lock.h>
18#include <linux/string.h>
19#include <asm/uaccess.h>
20
21#include <linux/coda.h>
22#include <linux/coda_linux.h>
23#include <linux/coda_fs_i.h>
24#include <linux/coda_psdev.h>
25#include <linux/coda_proc.h>
26
27/* if CODA_STORE fails with EOPNOTSUPP, venus clearly doesn't support
28 * CODA_STORE/CODA_RELEASE and we fall back on using the CODA_CLOSE upcall */
29static int use_coda_close;
30
31static ssize_t
32coda_file_read(struct file *coda_file, char __user *buf, size_t count, loff_t *ppos)
33{
34 struct coda_file_info *cfi;
35 struct file *host_file;
36
37 cfi = CODA_FTOC(coda_file);
38 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
39 host_file = cfi->cfi_container;
40
41 if (!host_file->f_op || !host_file->f_op->read)
42 return -EINVAL;
43
44 return host_file->f_op->read(host_file, buf, count, ppos);
45}
46
47static ssize_t
48coda_file_sendfile(struct file *coda_file, loff_t *ppos, size_t count,
49 read_actor_t actor, void *target)
50{
51 struct coda_file_info *cfi;
52 struct file *host_file;
53
54 cfi = CODA_FTOC(coda_file);
55 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
56 host_file = cfi->cfi_container;
57
58 if (!host_file->f_op || !host_file->f_op->sendfile)
59 return -EINVAL;
60
61 return host_file->f_op->sendfile(host_file, ppos, count, actor, target);
62}
63
64static ssize_t
65coda_file_write(struct file *coda_file, const char __user *buf, size_t count, loff_t *ppos)
66{
67 struct inode *host_inode, *coda_inode = coda_file->f_dentry->d_inode;
68 struct coda_file_info *cfi;
69 struct file *host_file;
70 ssize_t ret;
71
72 cfi = CODA_FTOC(coda_file);
73 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
74 host_file = cfi->cfi_container;
75
76 if (!host_file->f_op || !host_file->f_op->write)
77 return -EINVAL;
78
79 host_inode = host_file->f_dentry->d_inode;
80 down(&coda_inode->i_sem);
81
82 ret = host_file->f_op->write(host_file, buf, count, ppos);
83
84 coda_inode->i_size = host_inode->i_size;
85 coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
86 coda_inode->i_mtime = coda_inode->i_ctime = CURRENT_TIME_SEC;
87 up(&coda_inode->i_sem);
88
89 return ret;
90}
91
92static int
93coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
94{
95 struct coda_file_info *cfi;
96 struct coda_inode_info *cii;
97 struct file *host_file;
98 struct inode *coda_inode, *host_inode;
99
100 cfi = CODA_FTOC(coda_file);
101 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
102 host_file = cfi->cfi_container;
103
104 if (!host_file->f_op || !host_file->f_op->mmap)
105 return -ENODEV;
106
107 coda_inode = coda_file->f_dentry->d_inode;
108 host_inode = host_file->f_dentry->d_inode;
109 coda_file->f_mapping = host_file->f_mapping;
110 if (coda_inode->i_mapping == &coda_inode->i_data)
111 coda_inode->i_mapping = host_inode->i_mapping;
112
113 /* only allow additional mmaps as long as userspace isn't changing
114 * the container file on us! */
115 else if (coda_inode->i_mapping != host_inode->i_mapping)
116 return -EBUSY;
117
118 /* keep track of how often the coda_inode/host_file has been mmapped */
119 cii = ITOC(coda_inode);
120 cii->c_mapcount++;
121 cfi->cfi_mapcount++;
122
123 return host_file->f_op->mmap(host_file, vma);
124}
125
126int coda_open(struct inode *coda_inode, struct file *coda_file)
127{
128 struct file *host_file = NULL;
129 int error;
130 unsigned short flags = coda_file->f_flags & (~O_EXCL);
131 unsigned short coda_flags = coda_flags_to_cflags(flags);
132 struct coda_file_info *cfi;
133
134 coda_vfs_stat.open++;
135
136 cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL);
137 if (!cfi) {
138 unlock_kernel();
139 return -ENOMEM;
140 }
141
142 lock_kernel();
143
144 error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
145 &host_file);
146 if (error || !host_file) {
147 kfree(cfi);
148 unlock_kernel();
149 return error;
150 }
151
152 host_file->f_flags |= coda_file->f_flags & (O_APPEND | O_SYNC);
153
154 cfi->cfi_magic = CODA_MAGIC;
155 cfi->cfi_mapcount = 0;
156 cfi->cfi_container = host_file;
157
158 BUG_ON(coda_file->private_data != NULL);
159 coda_file->private_data = cfi;
160
161 unlock_kernel();
162 return 0;
163}
164
165int coda_flush(struct file *coda_file)
166{
167 unsigned short flags = coda_file->f_flags & ~O_EXCL;
168 unsigned short coda_flags = coda_flags_to_cflags(flags);
169 struct coda_file_info *cfi;
170 struct inode *coda_inode;
171 int err = 0, fcnt;
172
173 lock_kernel();
174
175 coda_vfs_stat.flush++;
176
177 /* last close semantics */
178 fcnt = file_count(coda_file);
179 if (fcnt > 1)
180 goto out;
181
182 /* No need to make an upcall when we have not made any modifications
183 * to the file */
184 if ((coda_file->f_flags & O_ACCMODE) == O_RDONLY)
185 goto out;
186
187 if (use_coda_close)
188 goto out;
189
190 cfi = CODA_FTOC(coda_file);
191 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
192
193 coda_inode = coda_file->f_dentry->d_inode;
194
195 err = venus_store(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
196 coda_file->f_uid);
197
198 if (err == -EOPNOTSUPP) {
199 use_coda_close = 1;
200 err = 0;
201 }
202
203out:
204 unlock_kernel();
205 return err;
206}
207
208int coda_release(struct inode *coda_inode, struct file *coda_file)
209{
210 unsigned short flags = (coda_file->f_flags) & (~O_EXCL);
211 unsigned short coda_flags = coda_flags_to_cflags(flags);
212 struct coda_file_info *cfi;
213 struct coda_inode_info *cii;
214 struct inode *host_inode;
215 int err = 0;
216
217 lock_kernel();
218 coda_vfs_stat.release++;
219
220 if (!use_coda_close) {
221 err = venus_release(coda_inode->i_sb, coda_i2f(coda_inode),
222 coda_flags);
223 if (err == -EOPNOTSUPP) {
224 use_coda_close = 1;
225 err = 0;
226 }
227 }
228
229 cfi = CODA_FTOC(coda_file);
230 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
231
232 if (use_coda_close)
233 err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
234 coda_flags, coda_file->f_uid);
235
236 host_inode = cfi->cfi_container->f_dentry->d_inode;
237 cii = ITOC(coda_inode);
238
239 /* did we mmap this file? */
240 if (coda_inode->i_mapping == &host_inode->i_data) {
241 cii->c_mapcount -= cfi->cfi_mapcount;
242 if (!cii->c_mapcount)
243 coda_inode->i_mapping = &coda_inode->i_data;
244 }
245
246 fput(cfi->cfi_container);
247 kfree(coda_file->private_data);
248 coda_file->private_data = NULL;
249
250 unlock_kernel();
251 return err;
252}
253
254int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
255{
256 struct file *host_file;
257 struct dentry *host_dentry;
258 struct inode *host_inode, *coda_inode = coda_dentry->d_inode;
259 struct coda_file_info *cfi;
260 int err = 0;
261
262 if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
263 S_ISLNK(coda_inode->i_mode)))
264 return -EINVAL;
265
266 cfi = CODA_FTOC(coda_file);
267 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
268 host_file = cfi->cfi_container;
269
270 coda_vfs_stat.fsync++;
271
272 if (host_file->f_op && host_file->f_op->fsync) {
273 host_dentry = host_file->f_dentry;
274 host_inode = host_dentry->d_inode;
275 down(&host_inode->i_sem);
276 err = host_file->f_op->fsync(host_file, host_dentry, datasync);
277 up(&host_inode->i_sem);
278 }
279
280 if ( !err && !datasync ) {
281 lock_kernel();
282 err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
283 unlock_kernel();
284 }
285
286 return err;
287}
288
289struct file_operations coda_file_operations = {
290 .llseek = generic_file_llseek,
291 .read = coda_file_read,
292 .write = coda_file_write,
293 .mmap = coda_file_mmap,
294 .open = coda_open,
295 .flush = coda_flush,
296 .release = coda_release,
297 .fsync = coda_fsync,
298 .sendfile = coda_file_sendfile,
299};
300
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
new file mode 100644
index 000000000000..04a73fb4848f
--- /dev/null
+++ b/fs/coda/inode.c
@@ -0,0 +1,321 @@
1/*
2 * Super block/filesystem wide operations
3 *
4 * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and
5 * Michael Callahan <callahan@maths.ox.ac.uk>
6 *
7 * Rewritten for Linux 2.1. Peter Braam <braam@cs.cmu.edu>
8 * Copyright (C) Carnegie Mellon University
9 */
10
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/mm.h>
14#include <linux/string.h>
15#include <linux/stat.h>
16#include <linux/errno.h>
17#include <linux/unistd.h>
18#include <linux/smp_lock.h>
19#include <linux/file.h>
20#include <linux/vfs.h>
21
22#include <asm/system.h>
23#include <asm/uaccess.h>
24
25#include <linux/fs.h>
26#include <linux/vmalloc.h>
27
28#include <linux/coda.h>
29#include <linux/coda_linux.h>
30#include <linux/coda_psdev.h>
31#include <linux/coda_fs_i.h>
32#include <linux/coda_cache.h>
33
34/* VFS super_block ops */
35static void coda_clear_inode(struct inode *);
36static void coda_put_super(struct super_block *);
37static int coda_statfs(struct super_block *sb, struct kstatfs *buf);
38
39static kmem_cache_t * coda_inode_cachep;
40
41static struct inode *coda_alloc_inode(struct super_block *sb)
42{
43 struct coda_inode_info *ei;
44 ei = (struct coda_inode_info *)kmem_cache_alloc(coda_inode_cachep, SLAB_KERNEL);
45 if (!ei)
46 return NULL;
47 memset(&ei->c_fid, 0, sizeof(struct CodaFid));
48 ei->c_flags = 0;
49 ei->c_uid = 0;
50 ei->c_cached_perm = 0;
51 return &ei->vfs_inode;
52}
53
54static void coda_destroy_inode(struct inode *inode)
55{
56 kmem_cache_free(coda_inode_cachep, ITOC(inode));
57}
58
59static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
60{
61 struct coda_inode_info *ei = (struct coda_inode_info *) foo;
62
63 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
64 SLAB_CTOR_CONSTRUCTOR)
65 inode_init_once(&ei->vfs_inode);
66}
67
68int coda_init_inodecache(void)
69{
70 coda_inode_cachep = kmem_cache_create("coda_inode_cache",
71 sizeof(struct coda_inode_info),
72 0, SLAB_RECLAIM_ACCOUNT,
73 init_once, NULL);
74 if (coda_inode_cachep == NULL)
75 return -ENOMEM;
76 return 0;
77}
78
79void coda_destroy_inodecache(void)
80{
81 if (kmem_cache_destroy(coda_inode_cachep))
82 printk(KERN_INFO "coda_inode_cache: not all structures were freed\n");
83}
84
85static int coda_remount(struct super_block *sb, int *flags, char *data)
86{
87 *flags |= MS_NODIRATIME;
88 return 0;
89}
90
91/* exported operations */
92static struct super_operations coda_super_operations =
93{
94 .alloc_inode = coda_alloc_inode,
95 .destroy_inode = coda_destroy_inode,
96 .clear_inode = coda_clear_inode,
97 .put_super = coda_put_super,
98 .statfs = coda_statfs,
99 .remount_fs = coda_remount,
100};
101
102static int get_device_index(struct coda_mount_data *data)
103{
104 struct file *file;
105 struct inode *inode;
106 int idx;
107
108 if(data == NULL) {
109 printk("coda_read_super: Bad mount data\n");
110 return -1;
111 }
112
113 if(data->version != CODA_MOUNT_VERSION) {
114 printk("coda_read_super: Bad mount version\n");
115 return -1;
116 }
117
118 file = fget(data->fd);
119 inode = NULL;
120 if(file)
121 inode = file->f_dentry->d_inode;
122
123 if(!inode || !S_ISCHR(inode->i_mode) ||
124 imajor(inode) != CODA_PSDEV_MAJOR) {
125 if(file)
126 fput(file);
127
128 printk("coda_read_super: Bad file\n");
129 return -1;
130 }
131
132 idx = iminor(inode);
133 fput(file);
134
135 if(idx < 0 || idx >= MAX_CODADEVS) {
136 printk("coda_read_super: Bad minor number\n");
137 return -1;
138 }
139
140 return idx;
141}
142
143static int coda_fill_super(struct super_block *sb, void *data, int silent)
144{
145 struct inode *root = NULL;
146 struct coda_sb_info *sbi = NULL;
147 struct venus_comm *vc = NULL;
148 struct CodaFid fid;
149 int error;
150 int idx;
151
152 idx = get_device_index((struct coda_mount_data *) data);
153
154 /* Ignore errors in data, for backward compatibility */
155 if(idx == -1)
156 idx = 0;
157
158 printk(KERN_INFO "coda_read_super: device index: %i\n", idx);
159
160 vc = &coda_comms[idx];
161 if (!vc->vc_inuse) {
162 printk("coda_read_super: No pseudo device\n");
163 return -EINVAL;
164 }
165
166 if ( vc->vc_sb ) {
167 printk("coda_read_super: Device already mounted\n");
168 return -EBUSY;
169 }
170
171 sbi = kmalloc(sizeof(struct coda_sb_info), GFP_KERNEL);
172 if(!sbi) {
173 return -ENOMEM;
174 }
175
176 vc->vc_sb = sb;
177
178 sbi->sbi_vcomm = vc;
179
180 sb->s_fs_info = sbi;
181 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
182 sb->s_blocksize = 1024; /* XXXXX what do we put here?? */
183 sb->s_blocksize_bits = 10;
184 sb->s_magic = CODA_SUPER_MAGIC;
185 sb->s_op = &coda_super_operations;
186
187 /* get root fid from Venus: this needs the root inode */
188 error = venus_rootfid(sb, &fid);
189 if ( error ) {
190 printk("coda_read_super: coda_get_rootfid failed with %d\n",
191 error);
192 goto error;
193 }
194 printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid));
195
196 /* make root inode */
197 error = coda_cnode_make(&root, &fid, sb);
198 if ( error || !root ) {
199 printk("Failure of coda_cnode_make for root: error %d\n", error);
200 goto error;
201 }
202
203 printk("coda_read_super: rootinode is %ld dev %s\n",
204 root->i_ino, root->i_sb->s_id);
205 sb->s_root = d_alloc_root(root);
206 if (!sb->s_root)
207 goto error;
208 return 0;
209
210 error:
211 if (sbi) {
212 kfree(sbi);
213 if(vc)
214 vc->vc_sb = NULL;
215 }
216 if (root)
217 iput(root);
218
219 return -EINVAL;
220}
221
222static void coda_put_super(struct super_block *sb)
223{
224 struct coda_sb_info *sbi;
225
226 sbi = coda_sbp(sb);
227 sbi->sbi_vcomm->vc_sb = NULL;
228
229 printk("Coda: Bye bye.\n");
230 kfree(sbi);
231}
232
233static void coda_clear_inode(struct inode *inode)
234{
235 coda_cache_clear_inode(inode);
236}
237
238int coda_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
239{
240 int err = coda_revalidate_inode(dentry);
241 if (!err)
242 generic_fillattr(dentry->d_inode, stat);
243 return err;
244}
245
246int coda_setattr(struct dentry *de, struct iattr *iattr)
247{
248 struct inode *inode = de->d_inode;
249 struct coda_vattr vattr;
250 int error;
251
252 lock_kernel();
253
254 memset(&vattr, 0, sizeof(vattr));
255
256 inode->i_ctime = CURRENT_TIME_SEC;
257 coda_iattr_to_vattr(iattr, &vattr);
258 vattr.va_type = C_VNON; /* cannot set type */
259
260 /* Venus is responsible for truncating the container-file!!! */
261 error = venus_setattr(inode->i_sb, coda_i2f(inode), &vattr);
262
263 if ( !error ) {
264 coda_vattr_to_iattr(inode, &vattr);
265 coda_cache_clear_inode(inode);
266 }
267
268 unlock_kernel();
269
270 return error;
271}
272
273struct inode_operations coda_file_inode_operations = {
274 .permission = coda_permission,
275 .getattr = coda_getattr,
276 .setattr = coda_setattr,
277};
278
279static int coda_statfs(struct super_block *sb, struct kstatfs *buf)
280{
281 int error;
282
283 lock_kernel();
284
285 error = venus_statfs(sb, buf);
286
287 unlock_kernel();
288
289 if (error) {
290 /* fake something like AFS does */
291 buf->f_blocks = 9000000;
292 buf->f_bfree = 9000000;
293 buf->f_bavail = 9000000;
294 buf->f_files = 9000000;
295 buf->f_ffree = 9000000;
296 }
297
298 /* and fill in the rest */
299 buf->f_type = CODA_SUPER_MAGIC;
300 buf->f_bsize = 1024;
301 buf->f_namelen = CODA_MAXNAMLEN;
302
303 return 0;
304}
305
306/* init_coda: used by filesystems.c to register coda */
307
308static struct super_block *coda_get_sb(struct file_system_type *fs_type,
309 int flags, const char *dev_name, void *data)
310{
311 return get_sb_nodev(fs_type, flags, data, coda_fill_super);
312}
313
314struct file_system_type coda_fs_type = {
315 .owner = THIS_MODULE,
316 .name = "coda",
317 .get_sb = coda_get_sb,
318 .kill_sb = kill_anon_super,
319 .fs_flags = FS_BINARY_MOUNTDATA,
320};
321
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
new file mode 100644
index 000000000000..127714936c66
--- /dev/null
+++ b/fs/coda/pioctl.c
@@ -0,0 +1,95 @@
1/*
2 * Pioctl operations for Coda.
3 * Original version: (C) 1996 Peter Braam
4 * Rewritten for Linux 2.1: (C) 1997 Carnegie Mellon University
5 *
6 * Carnegie Mellon encourages users of this code to contribute improvements
7 * to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
8 */
9
10#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/time.h>
13#include <linux/fs.h>
14#include <linux/stat.h>
15#include <linux/errno.h>
16#include <linux/string.h>
17#include <linux/namei.h>
18#include <linux/module.h>
19#include <asm/uaccess.h>
20
21#include <linux/coda.h>
22#include <linux/coda_linux.h>
23#include <linux/coda_fs_i.h>
24#include <linux/coda_psdev.h>
25
26/* pioctl ops */
27static int coda_ioctl_permission(struct inode *inode, int mask,
28 struct nameidata *nd);
29static int coda_pioctl(struct inode * inode, struct file * filp,
30 unsigned int cmd, unsigned long user_data);
31
32/* exported from this file */
33struct inode_operations coda_ioctl_inode_operations =
34{
35 .permission = coda_ioctl_permission,
36 .setattr = coda_setattr,
37};
38
39struct file_operations coda_ioctl_operations = {
40 .owner = THIS_MODULE,
41 .ioctl = coda_pioctl,
42};
43
44/* the coda pioctl inode ops */
45static int coda_ioctl_permission(struct inode *inode, int mask,
46 struct nameidata *nd)
47{
48 return 0;
49}
50
51static int coda_pioctl(struct inode * inode, struct file * filp,
52 unsigned int cmd, unsigned long user_data)
53{
54 struct nameidata nd;
55 int error;
56 struct PioctlData data;
57 struct inode *target_inode = NULL;
58 struct coda_inode_info *cnp;
59
60 /* get the Pioctl data arguments from user space */
61 if (copy_from_user(&data, (void __user *)user_data, sizeof(data))) {
62 return -EINVAL;
63 }
64
65 /*
66 * Look up the pathname. Note that the pathname is in
67 * user memory, and namei takes care of this
68 */
69 if ( data.follow ) {
70 error = user_path_walk(data.path, &nd);
71 } else {
72 error = user_path_walk_link(data.path, &nd);
73 }
74
75 if ( error ) {
76 return error;
77 } else {
78 target_inode = nd.dentry->d_inode;
79 }
80
81 /* return if it is not a Coda inode */
82 if ( target_inode->i_sb != inode->i_sb ) {
83 path_release(&nd);
84 return -EINVAL;
85 }
86
87 /* now proceed to make the upcall */
88 cnp = ITOC(target_inode);
89
90 error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data);
91
92 path_release(&nd);
93 return error;
94}
95
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
new file mode 100644
index 000000000000..ef001a9313e6
--- /dev/null
+++ b/fs/coda/psdev.c
@@ -0,0 +1,462 @@
1/*
2 * An implementation of a loadable kernel mode driver providing
3 * multiple kernel/user space bidirectional communications links.
4 *
5 * Author: Alan Cox <alan@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 * Adapted to become the Linux 2.0 Coda pseudo device
13 * Peter Braam <braam@maths.ox.ac.uk>
14 * Michael Callahan <mjc@emmy.smith.edu>
15 *
16 * Changes for Linux 2.1
17 * Copyright (c) 1997 Carnegie-Mellon University
18 */
19
20#include <linux/module.h>
21#include <linux/errno.h>
22#include <linux/kernel.h>
23#include <linux/major.h>
24#include <linux/time.h>
25#include <linux/slab.h>
26#include <linux/ioport.h>
27#include <linux/fcntl.h>
28#include <linux/delay.h>
29#include <linux/skbuff.h>
30#include <linux/proc_fs.h>
31#include <linux/devfs_fs_kernel.h>
32#include <linux/vmalloc.h>
33#include <linux/fs.h>
34#include <linux/file.h>
35#include <linux/poll.h>
36#include <linux/init.h>
37#include <linux/list.h>
38#include <linux/smp_lock.h>
39#include <linux/device.h>
40#include <asm/io.h>
41#include <asm/system.h>
42#include <asm/poll.h>
43#include <asm/uaccess.h>
44
45#include <linux/coda.h>
46#include <linux/coda_linux.h>
47#include <linux/coda_fs_i.h>
48#include <linux/coda_psdev.h>
49#include <linux/coda_proc.h>
50
51#define upc_free(r) kfree(r)
52
53/*
54 * Coda stuff
55 */
56extern struct file_system_type coda_fs_type;
57
58/* statistics */
59int coda_hard; /* allows signals during upcalls */
60unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */
61
62
63struct venus_comm coda_comms[MAX_CODADEVS];
64static struct class_simple *coda_psdev_class;
65
66/*
67 * Device operations
68 */
69
70static unsigned int coda_psdev_poll(struct file *file, poll_table * wait)
71{
72 struct venus_comm *vcp = (struct venus_comm *) file->private_data;
73 unsigned int mask = POLLOUT | POLLWRNORM;
74
75 poll_wait(file, &vcp->vc_waitq, wait);
76 if (!list_empty(&vcp->vc_pending))
77 mask |= POLLIN | POLLRDNORM;
78
79 return mask;
80}
81
82static int coda_psdev_ioctl(struct inode * inode, struct file * filp,
83 unsigned int cmd, unsigned long arg)
84{
85 unsigned int data;
86
87 switch(cmd) {
88 case CIOC_KERNEL_VERSION:
89 data = CODA_KERNEL_VERSION;
90 return put_user(data, (int __user *) arg);
91 default:
92 return -ENOTTY;
93 }
94
95 return 0;
96}
97
98/*
99 * Receive a message written by Venus to the psdev
100 */
101
102static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
103 size_t nbytes, loff_t *off)
104{
105 struct venus_comm *vcp = (struct venus_comm *) file->private_data;
106 struct upc_req *req = NULL;
107 struct upc_req *tmp;
108 struct list_head *lh;
109 struct coda_in_hdr hdr;
110 ssize_t retval = 0, count = 0;
111 int error;
112
113 /* Peek at the opcode, uniquefier */
114 if (copy_from_user(&hdr, buf, 2 * sizeof(u_long)))
115 return -EFAULT;
116
117 if (DOWNCALL(hdr.opcode)) {
118 struct super_block *sb = NULL;
119 union outputArgs *dcbuf;
120 int size = sizeof(*dcbuf);
121
122 sb = vcp->vc_sb;
123 if ( !sb ) {
124 count = nbytes;
125 goto out;
126 }
127
128 if ( nbytes < sizeof(struct coda_out_hdr) ) {
129 printk("coda_downcall opc %d uniq %d, not enough!\n",
130 hdr.opcode, hdr.unique);
131 count = nbytes;
132 goto out;
133 }
134 if ( nbytes > size ) {
135 printk("Coda: downcall opc %d, uniq %d, too much!",
136 hdr.opcode, hdr.unique);
137 nbytes = size;
138 }
139 CODA_ALLOC(dcbuf, union outputArgs *, nbytes);
140 if (copy_from_user(dcbuf, buf, nbytes)) {
141 CODA_FREE(dcbuf, nbytes);
142 retval = -EFAULT;
143 goto out;
144 }
145
146 /* what downcall errors does Venus handle ? */
147 lock_kernel();
148 error = coda_downcall(hdr.opcode, dcbuf, sb);
149 unlock_kernel();
150
151 CODA_FREE(dcbuf, nbytes);
152 if (error) {
153 printk("psdev_write: coda_downcall error: %d\n", error);
154 retval = error;
155 goto out;
156 }
157 count = nbytes;
158 goto out;
159 }
160
161 /* Look for the message on the processing queue. */
162 lock_kernel();
163 list_for_each(lh, &vcp->vc_processing) {
164 tmp = list_entry(lh, struct upc_req , uc_chain);
165 if (tmp->uc_unique == hdr.unique) {
166 req = tmp;
167 list_del(&req->uc_chain);
168 break;
169 }
170 }
171 unlock_kernel();
172
173 if (!req) {
174 printk("psdev_write: msg (%d, %d) not found\n",
175 hdr.opcode, hdr.unique);
176 retval = -ESRCH;
177 goto out;
178 }
179
180 /* move data into response buffer. */
181 if (req->uc_outSize < nbytes) {
182 printk("psdev_write: too much cnt: %d, cnt: %ld, opc: %d, uniq: %d.\n",
183 req->uc_outSize, (long)nbytes, hdr.opcode, hdr.unique);
184 nbytes = req->uc_outSize; /* don't have more space! */
185 }
186 if (copy_from_user(req->uc_data, buf, nbytes)) {
187 req->uc_flags |= REQ_ABORT;
188 wake_up(&req->uc_sleep);
189 retval = -EFAULT;
190 goto out;
191 }
192
193 /* adjust outsize. is this useful ?? */
194 req->uc_outSize = nbytes;
195 req->uc_flags |= REQ_WRITE;
196 count = nbytes;
197
198 /* Convert filedescriptor into a file handle */
199 if (req->uc_opcode == CODA_OPEN_BY_FD) {
200 struct coda_open_by_fd_out *outp =
201 (struct coda_open_by_fd_out *)req->uc_data;
202 outp->fh = fget(outp->fd);
203 }
204
205 wake_up(&req->uc_sleep);
206out:
207 return(count ? count : retval);
208}
209
210/*
211 * Read a message from the kernel to Venus
212 */
213
214static ssize_t coda_psdev_read(struct file * file, char __user * buf,
215 size_t nbytes, loff_t *off)
216{
217 DECLARE_WAITQUEUE(wait, current);
218 struct venus_comm *vcp = (struct venus_comm *) file->private_data;
219 struct upc_req *req;
220 ssize_t retval = 0, count = 0;
221
222 if (nbytes == 0)
223 return 0;
224
225 lock_kernel();
226
227 add_wait_queue(&vcp->vc_waitq, &wait);
228 set_current_state(TASK_INTERRUPTIBLE);
229
230 while (list_empty(&vcp->vc_pending)) {
231 if (file->f_flags & O_NONBLOCK) {
232 retval = -EAGAIN;
233 break;
234 }
235 if (signal_pending(current)) {
236 retval = -ERESTARTSYS;
237 break;
238 }
239 schedule();
240 }
241
242 set_current_state(TASK_RUNNING);
243 remove_wait_queue(&vcp->vc_waitq, &wait);
244
245 if (retval)
246 goto out;
247
248 req = list_entry(vcp->vc_pending.next, struct upc_req,uc_chain);
249 list_del(&req->uc_chain);
250
251 /* Move the input args into userspace */
252 count = req->uc_inSize;
253 if (nbytes < req->uc_inSize) {
254 printk ("psdev_read: Venus read %ld bytes of %d in message\n",
255 (long)nbytes, req->uc_inSize);
256 count = nbytes;
257 }
258
259 if (copy_to_user(buf, req->uc_data, count))
260 retval = -EFAULT;
261
262 /* If request was not a signal, enqueue and don't free */
263 if (!(req->uc_flags & REQ_ASYNC)) {
264 req->uc_flags |= REQ_READ;
265 list_add(&(req->uc_chain), vcp->vc_processing.prev);
266 goto out;
267 }
268
269 CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
270 upc_free(req);
271out:
272 unlock_kernel();
273 return (count ? count : retval);
274}
275
276static int coda_psdev_open(struct inode * inode, struct file * file)
277{
278 struct venus_comm *vcp;
279 int idx;
280
281 lock_kernel();
282 idx = iminor(inode);
283 if(idx >= MAX_CODADEVS) {
284 unlock_kernel();
285 return -ENODEV;
286 }
287
288 vcp = &coda_comms[idx];
289 if(vcp->vc_inuse) {
290 unlock_kernel();
291 return -EBUSY;
292 }
293
294 if (!vcp->vc_inuse++) {
295 INIT_LIST_HEAD(&vcp->vc_pending);
296 INIT_LIST_HEAD(&vcp->vc_processing);
297 init_waitqueue_head(&vcp->vc_waitq);
298 vcp->vc_sb = NULL;
299 vcp->vc_seq = 0;
300 }
301
302 file->private_data = vcp;
303
304 unlock_kernel();
305 return 0;
306}
307
308
309static int coda_psdev_release(struct inode * inode, struct file * file)
310{
311 struct venus_comm *vcp = (struct venus_comm *) file->private_data;
312 struct upc_req *req, *tmp;
313
314 lock_kernel();
315 if ( !vcp->vc_inuse ) {
316 unlock_kernel();
317 printk("psdev_release: Not open.\n");
318 return -1;
319 }
320
321 if (--vcp->vc_inuse) {
322 unlock_kernel();
323 return 0;
324 }
325
326 /* Wakeup clients so they can return. */
327 list_for_each_entry_safe(req, tmp, &vcp->vc_pending, uc_chain) {
328 /* Async requests need to be freed here */
329 if (req->uc_flags & REQ_ASYNC) {
330 CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
331 upc_free(req);
332 continue;
333 }
334 req->uc_flags |= REQ_ABORT;
335 wake_up(&req->uc_sleep);
336 }
337
338 list_for_each_entry(req, &vcp->vc_processing, uc_chain) {
339 req->uc_flags |= REQ_ABORT;
340 wake_up(&req->uc_sleep);
341 }
342
343 unlock_kernel();
344 return 0;
345}
346
347
348static struct file_operations coda_psdev_fops = {
349 .owner = THIS_MODULE,
350 .read = coda_psdev_read,
351 .write = coda_psdev_write,
352 .poll = coda_psdev_poll,
353 .ioctl = coda_psdev_ioctl,
354 .open = coda_psdev_open,
355 .release = coda_psdev_release,
356};
357
358static int init_coda_psdev(void)
359{
360 int i, err = 0;
361 if (register_chrdev(CODA_PSDEV_MAJOR, "coda", &coda_psdev_fops)) {
362 printk(KERN_ERR "coda_psdev: unable to get major %d\n",
363 CODA_PSDEV_MAJOR);
364 return -EIO;
365 }
366 coda_psdev_class = class_simple_create(THIS_MODULE, "coda");
367 if (IS_ERR(coda_psdev_class)) {
368 err = PTR_ERR(coda_psdev_class);
369 goto out_chrdev;
370 }
371 devfs_mk_dir ("coda");
372 for (i = 0; i < MAX_CODADEVS; i++) {
373 class_simple_device_add(coda_psdev_class, MKDEV(CODA_PSDEV_MAJOR,i),
374 NULL, "cfs%d", i);
375 err = devfs_mk_cdev(MKDEV(CODA_PSDEV_MAJOR, i),
376 S_IFCHR|S_IRUSR|S_IWUSR, "coda/%d", i);
377 if (err)
378 goto out_class;
379 }
380 coda_sysctl_init();
381 goto out;
382
383out_class:
384 for (i = 0; i < MAX_CODADEVS; i++)
385 class_simple_device_remove(MKDEV(CODA_PSDEV_MAJOR, i));
386 class_simple_destroy(coda_psdev_class);
387out_chrdev:
388 unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
389out:
390 return err;
391}
392
393
394MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
395MODULE_LICENSE("GPL");
396
397extern int coda_init_inodecache(void);
398extern void coda_destroy_inodecache(void);
399static int __init init_coda(void)
400{
401 int status;
402 int i;
403 printk(KERN_INFO "Coda Kernel/Venus communications, "
404#ifdef CONFIG_CODA_FS_OLD_API
405 "v5.3.20"
406#else
407 "v6.0.0"
408#endif
409 ", coda@cs.cmu.edu\n");
410
411 status = coda_init_inodecache();
412 if (status)
413 goto out2;
414 status = init_coda_psdev();
415 if ( status ) {
416 printk("Problem (%d) in init_coda_psdev\n", status);
417 goto out1;
418 }
419
420 status = register_filesystem(&coda_fs_type);
421 if (status) {
422 printk("coda: failed to register filesystem!\n");
423 goto out;
424 }
425 return 0;
426out:
427 for (i = 0; i < MAX_CODADEVS; i++) {
428 class_simple_device_remove(MKDEV(CODA_PSDEV_MAJOR, i));
429 devfs_remove("coda/%d", i);
430 }
431 class_simple_destroy(coda_psdev_class);
432 devfs_remove("coda");
433 unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
434 coda_sysctl_clean();
435out1:
436 coda_destroy_inodecache();
437out2:
438 return status;
439}
440
441static void __exit exit_coda(void)
442{
443 int err, i;
444
445 err = unregister_filesystem(&coda_fs_type);
446 if ( err != 0 ) {
447 printk("coda: failed to unregister filesystem\n");
448 }
449 for (i = 0; i < MAX_CODADEVS; i++) {
450 class_simple_device_remove(MKDEV(CODA_PSDEV_MAJOR, i));
451 devfs_remove("coda/%d", i);
452 }
453 class_simple_destroy(coda_psdev_class);
454 devfs_remove("coda");
455 unregister_chrdev(CODA_PSDEV_MAJOR, "coda");
456 coda_sysctl_clean();
457 coda_destroy_inodecache();
458}
459
460module_init(init_coda);
461module_exit(exit_coda);
462
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
new file mode 100644
index 000000000000..b35e5bbd9c99
--- /dev/null
+++ b/fs/coda/symlink.c
@@ -0,0 +1,55 @@
1/*
2 * Symlink inode operations for Coda filesystem
3 * Original version: (C) 1996 P. Braam and M. Callahan
4 * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
5 *
6 * Carnegie Mellon encourages users to contribute improvements to
7 * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
8 */
9
10#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/time.h>
13#include <linux/fs.h>
14#include <linux/stat.h>
15#include <linux/errno.h>
16#include <linux/pagemap.h>
17#include <linux/smp_lock.h>
18
19#include <linux/coda.h>
20#include <linux/coda_linux.h>
21#include <linux/coda_psdev.h>
22#include <linux/coda_fs_i.h>
23#include <linux/coda_proc.h>
24
25static int coda_symlink_filler(struct file *file, struct page *page)
26{
27 struct inode *inode = page->mapping->host;
28 int error;
29 struct coda_inode_info *cii;
30 unsigned int len = PAGE_SIZE;
31 char *p = kmap(page);
32
33 lock_kernel();
34 cii = ITOC(inode);
35 coda_vfs_stat.follow_link++;
36
37 error = venus_readlink(inode->i_sb, &cii->c_fid, p, &len);
38 unlock_kernel();
39 if (error)
40 goto fail;
41 SetPageUptodate(page);
42 kunmap(page);
43 unlock_page(page);
44 return 0;
45
46fail:
47 SetPageError(page);
48 kunmap(page);
49 unlock_page(page);
50 return error;
51}
52
53struct address_space_operations coda_symlink_aops = {
54 .readpage = coda_symlink_filler,
55};
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c
new file mode 100644
index 000000000000..f0b10757288f
--- /dev/null
+++ b/fs/coda/sysctl.c
@@ -0,0 +1,254 @@
1/*
2 * Sysctl operations for Coda filesystem
3 * Original version: (C) 1996 P. Braam and M. Callahan
4 * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
5 *
6 * Carnegie Mellon encourages users to contribute improvements to
7 * the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
8 *
9 * CODA operation statistics
10 * (c) March, 1998 Zhanyong Wan <zhanyong.wan@yale.edu>
11 *
12 */
13
14#include <linux/config.h>
15#include <linux/time.h>
16#include <linux/mm.h>
17#include <linux/sysctl.h>
18#include <linux/proc_fs.h>
19#include <linux/slab.h>
20#include <linux/stat.h>
21#include <linux/ctype.h>
22#include <linux/bitops.h>
23#include <asm/uaccess.h>
24#include <linux/utsname.h>
25#include <linux/module.h>
26
27#include <linux/coda.h>
28#include <linux/coda_linux.h>
29#include <linux/coda_fs_i.h>
30#include <linux/coda_psdev.h>
31#include <linux/coda_cache.h>
32#include <linux/coda_proc.h>
33
34static struct ctl_table_header *fs_table_header;
35
36#define FS_CODA 1 /* Coda file system */
37
38#define CODA_TIMEOUT 3 /* timeout on upcalls to become intrble */
39#define CODA_HARD 5 /* mount type "hard" or "soft" */
40#define CODA_VFS 6 /* vfs statistics */
41#define CODA_CACHE_INV 9 /* cache invalidation statistics */
42#define CODA_FAKE_STATFS 10 /* don't query venus for actual cache usage */
43
44struct coda_vfs_stats coda_vfs_stat;
45static struct coda_cache_inv_stats coda_cache_inv_stat;
46
47static void reset_coda_vfs_stats( void )
48{
49 memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
50}
51
52static void reset_coda_cache_inv_stats( void )
53{
54 memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
55}
56
57static int do_reset_coda_vfs_stats( ctl_table * table, int write,
58 struct file * filp, void __user * buffer,
59 size_t * lenp, loff_t * ppos )
60{
61 if ( write ) {
62 reset_coda_vfs_stats();
63
64 *ppos += *lenp;
65 } else {
66 *lenp = 0;
67 }
68
69 return 0;
70}
71
72static int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
73 struct file * filp,
74 void __user * buffer,
75 size_t * lenp, loff_t * ppos )
76{
77 if ( write ) {
78 reset_coda_cache_inv_stats();
79
80 *ppos += *lenp;
81 } else {
82 *lenp = 0;
83 }
84
85 return 0;
86}
87
88static int coda_vfs_stats_get_info( char * buffer, char ** start,
89 off_t offset, int length)
90{
91 int len=0;
92 off_t begin;
93 struct coda_vfs_stats * ps = & coda_vfs_stat;
94
95 /* this works as long as we are below 1024 characters! */
96 len += sprintf( buffer,
97 "Coda VFS statistics\n"
98 "===================\n\n"
99 "File Operations:\n"
100 "\topen\t\t%9d\n"
101 "\tflush\t\t%9d\n"
102 "\trelease\t\t%9d\n"
103 "\tfsync\t\t%9d\n\n"
104 "Dir Operations:\n"
105 "\treaddir\t\t%9d\n\n"
106 "Inode Operations\n"
107 "\tcreate\t\t%9d\n"
108 "\tlookup\t\t%9d\n"
109 "\tlink\t\t%9d\n"
110 "\tunlink\t\t%9d\n"
111 "\tsymlink\t\t%9d\n"
112 "\tmkdir\t\t%9d\n"
113 "\trmdir\t\t%9d\n"
114 "\trename\t\t%9d\n"
115 "\tpermission\t%9d\n",
116
117 /* file operations */
118 ps->open,
119 ps->flush,
120 ps->release,
121 ps->fsync,
122
123 /* dir operations */
124 ps->readdir,
125
126 /* inode operations */
127 ps->create,
128 ps->lookup,
129 ps->link,
130 ps->unlink,
131 ps->symlink,
132 ps->mkdir,
133 ps->rmdir,
134 ps->rename,
135 ps->permission);
136
137 begin = offset;
138 *start = buffer + begin;
139 len -= begin;
140
141 if ( len > length )
142 len = length;
143 if ( len < 0 )
144 len = 0;
145
146 return len;
147}
148
149static int coda_cache_inv_stats_get_info( char * buffer, char ** start,
150 off_t offset, int length)
151{
152 int len=0;
153 off_t begin;
154 struct coda_cache_inv_stats * ps = & coda_cache_inv_stat;
155
156 /* this works as long as we are below 1024 characters! */
157 len += sprintf( buffer,
158 "Coda cache invalidation statistics\n"
159 "==================================\n\n"
160 "flush\t\t%9d\n"
161 "purge user\t%9d\n"
162 "zap_dir\t\t%9d\n"
163 "zap_file\t%9d\n"
164 "zap_vnode\t%9d\n"
165 "purge_fid\t%9d\n"
166 "replace\t\t%9d\n",
167 ps->flush,
168 ps->purge_user,
169 ps->zap_dir,
170 ps->zap_file,
171 ps->zap_vnode,
172 ps->purge_fid,
173 ps->replace );
174
175 begin = offset;
176 *start = buffer + begin;
177 len -= begin;
178
179 if ( len > length )
180 len = length;
181 if ( len < 0 )
182 len = 0;
183
184 return len;
185}
186
187static ctl_table coda_table[] = {
188 {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &proc_dointvec},
189 {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &proc_dointvec},
190 {CODA_VFS, "vfs_stats", NULL, 0, 0644, NULL, &do_reset_coda_vfs_stats},
191 {CODA_CACHE_INV, "cache_inv_stats", NULL, 0, 0644, NULL, &do_reset_coda_cache_inv_stats},
192 {CODA_FAKE_STATFS, "fake_statfs", &coda_fake_statfs, sizeof(int), 0600, NULL, &proc_dointvec},
193 { 0 }
194};
195
196static ctl_table fs_table[] = {
197 {FS_CODA, "coda", NULL, 0, 0555, coda_table},
198 {0}
199};
200
201
202#ifdef CONFIG_PROC_FS
203
204/*
205 target directory structure:
206 /proc/fs (see linux/fs/proc/root.c)
207 /proc/fs/coda
208 /proc/fs/coda/{vfs_stats,
209
210*/
211
212static struct proc_dir_entry* proc_fs_coda;
213
214#endif
215
216#define coda_proc_create(name,get_info) \
217 create_proc_info_entry(name, 0, proc_fs_coda, get_info)
218
219void coda_sysctl_init(void)
220{
221 reset_coda_vfs_stats();
222 reset_coda_cache_inv_stats();
223
224#ifdef CONFIG_PROC_FS
225 proc_fs_coda = proc_mkdir("coda", proc_root_fs);
226 if (proc_fs_coda) {
227 proc_fs_coda->owner = THIS_MODULE;
228 coda_proc_create("vfs_stats", coda_vfs_stats_get_info);
229 coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info);
230 }
231#endif
232
233#ifdef CONFIG_SYSCTL
234 if ( !fs_table_header )
235 fs_table_header = register_sysctl_table(fs_table, 0);
236#endif
237}
238
239void coda_sysctl_clean(void)
240{
241
242#ifdef CONFIG_SYSCTL
243 if ( fs_table_header ) {
244 unregister_sysctl_table(fs_table_header);
245 fs_table_header = NULL;
246 }
247#endif
248
249#ifdef CONFIG_PROC_FS
250 remove_proc_entry("cache_inv_stats", proc_fs_coda);
251 remove_proc_entry("vfs_stats", proc_fs_coda);
252 remove_proc_entry("coda", proc_root_fs);
253#endif
254}
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
new file mode 100644
index 000000000000..1bae99650a91
--- /dev/null
+++ b/fs/coda/upcall.c
@@ -0,0 +1,914 @@
1/*
2 * Mostly platform independent upcall operations to Venus:
3 * -- upcalls
4 * -- upcall routines
5 *
6 * Linux 2.0 version
7 * Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk>,
8 * Michael Callahan <callahan@maths.ox.ac.uk>
9 *
10 * Redone for Linux 2.1
11 * Copyright (C) 1997 Carnegie Mellon University
12 *
13 * Carnegie Mellon University encourages users of this code to contribute
14 * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
15 */
16
17#include <asm/system.h>
18#include <linux/signal.h>
19
20#include <linux/types.h>
21#include <linux/kernel.h>
22#include <linux/mm.h>
23#include <linux/time.h>
24#include <linux/fs.h>
25#include <linux/file.h>
26#include <linux/stat.h>
27#include <linux/errno.h>
28#include <linux/string.h>
29#include <asm/uaccess.h>
30#include <linux/vmalloc.h>
31#include <linux/vfs.h>
32
33#include <linux/coda.h>
34#include <linux/coda_linux.h>
35#include <linux/coda_psdev.h>
36#include <linux/coda_fs_i.h>
37#include <linux/coda_cache.h>
38#include <linux/coda_proc.h>
39
40#define upc_alloc() kmalloc(sizeof(struct upc_req), GFP_KERNEL)
41#define upc_free(r) kfree(r)
42
43static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
44 union inputArgs *buffer);
45
46static void *alloc_upcall(int opcode, int size)
47{
48 union inputArgs *inp;
49
50 CODA_ALLOC(inp, union inputArgs *, size);
51 if (!inp)
52 return ERR_PTR(-ENOMEM);
53
54 inp->ih.opcode = opcode;
55 inp->ih.pid = current->pid;
56 inp->ih.pgid = process_group(current);
57#ifdef CONFIG_CODA_FS_OLD_API
58 memset(&inp->ih.cred, 0, sizeof(struct coda_cred));
59 inp->ih.cred.cr_fsuid = current->fsuid;
60#else
61 inp->ih.uid = current->fsuid;
62#endif
63 return (void*)inp;
64}
65
66#define UPARG(op)\
67do {\
68 inp = (union inputArgs *)alloc_upcall(op, insize); \
69 if (IS_ERR(inp)) { return PTR_ERR(inp); }\
70 outp = (union outputArgs *)(inp); \
71 outsize = insize; \
72} while (0)
73
74#define INSIZE(tag) sizeof(struct coda_ ## tag ## _in)
75#define OUTSIZE(tag) sizeof(struct coda_ ## tag ## _out)
76#define SIZE(tag) max_t(unsigned int, INSIZE(tag), OUTSIZE(tag))
77
78
79/* the upcalls */
80int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
81{
82 union inputArgs *inp;
83 union outputArgs *outp;
84 int insize, outsize, error;
85
86 insize = SIZE(root);
87 UPARG(CODA_ROOT);
88
89 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
90
91 if (error) {
92 printk("coda_get_rootfid: error %d\n", error);
93 } else {
94 *fidp = outp->coda_root.VFid;
95 }
96
97 CODA_FREE(inp, insize);
98 return error;
99}
100
101int venus_getattr(struct super_block *sb, struct CodaFid *fid,
102 struct coda_vattr *attr)
103{
104 union inputArgs *inp;
105 union outputArgs *outp;
106 int insize, outsize, error;
107
108 insize = SIZE(getattr);
109 UPARG(CODA_GETATTR);
110 inp->coda_getattr.VFid = *fid;
111
112 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
113
114 *attr = outp->coda_getattr.attr;
115
116 CODA_FREE(inp, insize);
117 return error;
118}
119
120int venus_setattr(struct super_block *sb, struct CodaFid *fid,
121 struct coda_vattr *vattr)
122{
123 union inputArgs *inp;
124 union outputArgs *outp;
125 int insize, outsize, error;
126
127 insize = SIZE(setattr);
128 UPARG(CODA_SETATTR);
129
130 inp->coda_setattr.VFid = *fid;
131 inp->coda_setattr.attr = *vattr;
132
133 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
134
135 CODA_FREE(inp, insize);
136 return error;
137}
138
139int venus_lookup(struct super_block *sb, struct CodaFid *fid,
140 const char *name, int length, int * type,
141 struct CodaFid *resfid)
142{
143 union inputArgs *inp;
144 union outputArgs *outp;
145 int insize, outsize, error;
146 int offset;
147
148 offset = INSIZE(lookup);
149 insize = max_t(unsigned int, offset + length +1, OUTSIZE(lookup));
150 UPARG(CODA_LOOKUP);
151
152 inp->coda_lookup.VFid = *fid;
153 inp->coda_lookup.name = offset;
154 inp->coda_lookup.flags = CLU_CASE_SENSITIVE;
155 /* send Venus a null terminated string */
156 memcpy((char *)(inp) + offset, name, length);
157 *((char *)inp + offset + length) = '\0';
158
159 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
160
161 *resfid = outp->coda_lookup.VFid;
162 *type = outp->coda_lookup.vtype;
163
164 CODA_FREE(inp, insize);
165 return error;
166}
167
168int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
169 vuid_t uid)
170{
171 union inputArgs *inp;
172 union outputArgs *outp;
173 int insize, outsize, error;
174#ifdef CONFIG_CODA_FS_OLD_API
175 struct coda_cred cred = { 0, };
176 cred.cr_fsuid = uid;
177#endif
178
179 insize = SIZE(store);
180 UPARG(CODA_STORE);
181
182#ifdef CONFIG_CODA_FS_OLD_API
183 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
184#else
185 inp->ih.uid = uid;
186#endif
187
188 inp->coda_store.VFid = *fid;
189 inp->coda_store.flags = flags;
190
191 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
192
193 CODA_FREE(inp, insize);
194 return error;
195}
196
197int venus_release(struct super_block *sb, struct CodaFid *fid, int flags)
198{
199 union inputArgs *inp;
200 union outputArgs *outp;
201 int insize, outsize, error;
202
203 insize = SIZE(release);
204 UPARG(CODA_RELEASE);
205
206 inp->coda_release.VFid = *fid;
207 inp->coda_release.flags = flags;
208
209 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
210
211 CODA_FREE(inp, insize);
212 return error;
213}
214
215int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
216 vuid_t uid)
217{
218 union inputArgs *inp;
219 union outputArgs *outp;
220 int insize, outsize, error;
221#ifdef CONFIG_CODA_FS_OLD_API
222 struct coda_cred cred = { 0, };
223 cred.cr_fsuid = uid;
224#endif
225
226 insize = SIZE(release);
227 UPARG(CODA_CLOSE);
228
229#ifdef CONFIG_CODA_FS_OLD_API
230 memcpy(&(inp->ih.cred), &cred, sizeof(cred));
231#else
232 inp->ih.uid = uid;
233#endif
234
235 inp->coda_close.VFid = *fid;
236 inp->coda_close.flags = flags;
237
238 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
239
240 CODA_FREE(inp, insize);
241 return error;
242}
243
244int venus_open(struct super_block *sb, struct CodaFid *fid,
245 int flags, struct file **fh)
246{
247 union inputArgs *inp;
248 union outputArgs *outp;
249 int insize, outsize, error;
250
251 insize = SIZE(open_by_fd);
252 UPARG(CODA_OPEN_BY_FD);
253
254 inp->coda_open.VFid = *fid;
255 inp->coda_open.flags = flags;
256
257 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
258
259 *fh = outp->coda_open_by_fd.fh;
260
261 CODA_FREE(inp, insize);
262 return error;
263}
264
265int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
266 const char *name, int length,
267 struct CodaFid *newfid, struct coda_vattr *attrs)
268{
269 union inputArgs *inp;
270 union outputArgs *outp;
271 int insize, outsize, error;
272 int offset;
273
274 offset = INSIZE(mkdir);
275 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(mkdir));
276 UPARG(CODA_MKDIR);
277
278 inp->coda_mkdir.VFid = *dirfid;
279 inp->coda_mkdir.attr = *attrs;
280 inp->coda_mkdir.name = offset;
281 /* Venus must get null terminated string */
282 memcpy((char *)(inp) + offset, name, length);
283 *((char *)inp + offset + length) = '\0';
284
285 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
286
287 *attrs = outp->coda_mkdir.attr;
288 *newfid = outp->coda_mkdir.VFid;
289
290 CODA_FREE(inp, insize);
291 return error;
292}
293
294
295int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
296 struct CodaFid *new_fid, size_t old_length,
297 size_t new_length, const char *old_name,
298 const char *new_name)
299{
300 union inputArgs *inp;
301 union outputArgs *outp;
302 int insize, outsize, error;
303 int offset, s;
304
305 offset = INSIZE(rename);
306 insize = max_t(unsigned int, offset + new_length + old_length + 8,
307 OUTSIZE(rename));
308 UPARG(CODA_RENAME);
309
310 inp->coda_rename.sourceFid = *old_fid;
311 inp->coda_rename.destFid = *new_fid;
312 inp->coda_rename.srcname = offset;
313
314 /* Venus must receive an null terminated string */
315 s = ( old_length & ~0x3) +4; /* round up to word boundary */
316 memcpy((char *)(inp) + offset, old_name, old_length);
317 *((char *)inp + offset + old_length) = '\0';
318
319 /* another null terminated string for Venus */
320 offset += s;
321 inp->coda_rename.destname = offset;
322 s = ( new_length & ~0x3) +4; /* round up to word boundary */
323 memcpy((char *)(inp) + offset, new_name, new_length);
324 *((char *)inp + offset + new_length) = '\0';
325
326 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
327
328 CODA_FREE(inp, insize);
329 return error;
330}
331
332int venus_create(struct super_block *sb, struct CodaFid *dirfid,
333 const char *name, int length, int excl, int mode,
334 struct CodaFid *newfid, struct coda_vattr *attrs)
335{
336 union inputArgs *inp;
337 union outputArgs *outp;
338 int insize, outsize, error;
339 int offset;
340
341 offset = INSIZE(create);
342 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(create));
343 UPARG(CODA_CREATE);
344
345 inp->coda_create.VFid = *dirfid;
346 inp->coda_create.attr.va_mode = mode;
347 inp->coda_create.excl = excl;
348 inp->coda_create.mode = mode;
349 inp->coda_create.name = offset;
350
351 /* Venus must get null terminated string */
352 memcpy((char *)(inp) + offset, name, length);
353 *((char *)inp + offset + length) = '\0';
354
355 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
356
357 *attrs = outp->coda_create.attr;
358 *newfid = outp->coda_create.VFid;
359
360 CODA_FREE(inp, insize);
361 return error;
362}
363
364int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
365 const char *name, int length)
366{
367 union inputArgs *inp;
368 union outputArgs *outp;
369 int insize, outsize, error;
370 int offset;
371
372 offset = INSIZE(rmdir);
373 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(rmdir));
374 UPARG(CODA_RMDIR);
375
376 inp->coda_rmdir.VFid = *dirfid;
377 inp->coda_rmdir.name = offset;
378 memcpy((char *)(inp) + offset, name, length);
379 *((char *)inp + offset + length) = '\0';
380
381 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
382
383 CODA_FREE(inp, insize);
384 return error;
385}
386
387int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
388 const char *name, int length)
389{
390 union inputArgs *inp;
391 union outputArgs *outp;
392 int error=0, insize, outsize, offset;
393
394 offset = INSIZE(remove);
395 insize = max_t(unsigned int, offset + length + 1, OUTSIZE(remove));
396 UPARG(CODA_REMOVE);
397
398 inp->coda_remove.VFid = *dirfid;
399 inp->coda_remove.name = offset;
400 memcpy((char *)(inp) + offset, name, length);
401 *((char *)inp + offset + length) = '\0';
402
403 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
404
405 CODA_FREE(inp, insize);
406 return error;
407}
408
409int venus_readlink(struct super_block *sb, struct CodaFid *fid,
410 char *buffer, int *length)
411{
412 union inputArgs *inp;
413 union outputArgs *outp;
414 int insize, outsize, error;
415 int retlen;
416 char *result;
417
418 insize = max_t(unsigned int,
419 INSIZE(readlink), OUTSIZE(readlink)+ *length + 1);
420 UPARG(CODA_READLINK);
421
422 inp->coda_readlink.VFid = *fid;
423
424 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
425
426 if (! error) {
427 retlen = outp->coda_readlink.count;
428 if ( retlen > *length )
429 retlen = *length;
430 *length = retlen;
431 result = (char *)outp + (long)outp->coda_readlink.data;
432 memcpy(buffer, result, retlen);
433 *(buffer + retlen) = '\0';
434 }
435
436 CODA_FREE(inp, insize);
437 return error;
438}
439
440
441
442int venus_link(struct super_block *sb, struct CodaFid *fid,
443 struct CodaFid *dirfid, const char *name, int len )
444{
445 union inputArgs *inp;
446 union outputArgs *outp;
447 int insize, outsize, error;
448 int offset;
449
450 offset = INSIZE(link);
451 insize = max_t(unsigned int, offset + len + 1, OUTSIZE(link));
452 UPARG(CODA_LINK);
453
454 inp->coda_link.sourceFid = *fid;
455 inp->coda_link.destFid = *dirfid;
456 inp->coda_link.tname = offset;
457
458 /* make sure strings are null terminated */
459 memcpy((char *)(inp) + offset, name, len);
460 *((char *)inp + offset + len) = '\0';
461
462 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
463
464 CODA_FREE(inp, insize);
465 return error;
466}
467
468int venus_symlink(struct super_block *sb, struct CodaFid *fid,
469 const char *name, int len,
470 const char *symname, int symlen)
471{
472 union inputArgs *inp;
473 union outputArgs *outp;
474 int insize, outsize, error;
475 int offset, s;
476
477 offset = INSIZE(symlink);
478 insize = max_t(unsigned int, offset + len + symlen + 8, OUTSIZE(symlink));
479 UPARG(CODA_SYMLINK);
480
481 /* inp->coda_symlink.attr = *tva; XXXXXX */
482 inp->coda_symlink.VFid = *fid;
483
484 /* Round up to word boundary and null terminate */
485 inp->coda_symlink.srcname = offset;
486 s = ( symlen & ~0x3 ) + 4;
487 memcpy((char *)(inp) + offset, symname, symlen);
488 *((char *)inp + offset + symlen) = '\0';
489
490 /* Round up to word boundary and null terminate */
491 offset += s;
492 inp->coda_symlink.tname = offset;
493 s = (len & ~0x3) + 4;
494 memcpy((char *)(inp) + offset, name, len);
495 *((char *)inp + offset + len) = '\0';
496
497 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
498
499 CODA_FREE(inp, insize);
500 return error;
501}
502
503int venus_fsync(struct super_block *sb, struct CodaFid *fid)
504{
505 union inputArgs *inp;
506 union outputArgs *outp;
507 int insize, outsize, error;
508
509 insize=SIZE(fsync);
510 UPARG(CODA_FSYNC);
511
512 inp->coda_fsync.VFid = *fid;
513 error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
514 &outsize, inp);
515
516 CODA_FREE(inp, insize);
517 return error;
518}
519
520int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
521{
522 union inputArgs *inp;
523 union outputArgs *outp;
524 int insize, outsize, error;
525
526 insize = SIZE(access);
527 UPARG(CODA_ACCESS);
528
529 inp->coda_access.VFid = *fid;
530 inp->coda_access.flags = mask;
531
532 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
533
534 CODA_FREE(inp, insize);
535 return error;
536}
537
538
539int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
540 unsigned int cmd, struct PioctlData *data)
541{
542 union inputArgs *inp;
543 union outputArgs *outp;
544 int insize, outsize, error;
545 int iocsize;
546
547 insize = VC_MAXMSGSIZE;
548 UPARG(CODA_IOCTL);
549
550 /* build packet for Venus */
551 if (data->vi.in_size > VC_MAXDATASIZE) {
552 error = -EINVAL;
553 goto exit;
554 }
555
556 if (data->vi.out_size > VC_MAXDATASIZE) {
557 error = -EINVAL;
558 goto exit;
559 }
560
561 inp->coda_ioctl.VFid = *fid;
562
563 /* the cmd field was mutated by increasing its size field to
564 * reflect the path and follow args. We need to subtract that
565 * out before sending the command to Venus. */
566 inp->coda_ioctl.cmd = (cmd & ~(PIOCPARM_MASK << 16));
567 iocsize = ((cmd >> 16) & PIOCPARM_MASK) - sizeof(char *) - sizeof(int);
568 inp->coda_ioctl.cmd |= (iocsize & PIOCPARM_MASK) << 16;
569
570 /* in->coda_ioctl.rwflag = flag; */
571 inp->coda_ioctl.len = data->vi.in_size;
572 inp->coda_ioctl.data = (char *)(INSIZE(ioctl));
573
574 /* get the data out of user space */
575 if ( copy_from_user((char*)inp + (long)inp->coda_ioctl.data,
576 data->vi.in, data->vi.in_size) ) {
577 error = -EINVAL;
578 goto exit;
579 }
580
581 error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
582 &outsize, inp);
583
584 if (error) {
585 printk("coda_pioctl: Venus returns: %d for %s\n",
586 error, coda_f2s(fid));
587 goto exit;
588 }
589
590 if (outsize < (long)outp->coda_ioctl.data + outp->coda_ioctl.len) {
591 error = -EINVAL;
592 goto exit;
593 }
594
595 /* Copy out the OUT buffer. */
596 if (outp->coda_ioctl.len > data->vi.out_size) {
597 error = -EINVAL;
598 goto exit;
599 }
600
601 /* Copy out the OUT buffer. */
602 if (copy_to_user(data->vi.out,
603 (char *)outp + (long)outp->coda_ioctl.data,
604 outp->coda_ioctl.len)) {
605 error = -EFAULT;
606 goto exit;
607 }
608
609 exit:
610 CODA_FREE(inp, insize);
611 return error;
612}
613
614int venus_statfs(struct super_block *sb, struct kstatfs *sfs)
615{
616 union inputArgs *inp;
617 union outputArgs *outp;
618 int insize, outsize, error;
619
620 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
621 UPARG(CODA_STATFS);
622
623 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
624
625 if (!error) {
626 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
627 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
628 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
629 sfs->f_files = outp->coda_statfs.stat.f_files;
630 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
631 } else {
632 printk("coda_statfs: Venus returns: %d\n", error);
633 }
634
635 CODA_FREE(inp, insize);
636 return error;
637}
638
639/*
640 * coda_upcall and coda_downcall routines.
641 *
642 */
643
644static inline void coda_waitfor_upcall(struct upc_req *vmp,
645 struct venus_comm *vcommp)
646{
647 DECLARE_WAITQUEUE(wait, current);
648
649 vmp->uc_posttime = jiffies;
650
651 add_wait_queue(&vmp->uc_sleep, &wait);
652 for (;;) {
653 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
654 set_current_state(TASK_INTERRUPTIBLE);
655 else
656 set_current_state(TASK_UNINTERRUPTIBLE);
657
658 /* venus died */
659 if ( !vcommp->vc_inuse )
660 break;
661
662 /* got a reply */
663 if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
664 break;
665
666 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
667 /* if this process really wants to die, let it go */
668 if ( sigismember(&(current->pending.signal), SIGKILL) ||
669 sigismember(&(current->pending.signal), SIGINT) )
670 break;
671 /* signal is present: after timeout always return
672 really smart idea, probably useless ... */
673 if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
674 break;
675 }
676 schedule();
677 }
678 remove_wait_queue(&vmp->uc_sleep, &wait);
679 set_current_state(TASK_RUNNING);
680
681 return;
682}
683
684
685/*
686 * coda_upcall will return an error in the case of
687 * failed communication with Venus _or_ will peek at Venus
688 * reply and return Venus' error.
689 *
690 * As venus has 2 types of errors, normal errors (positive) and internal
691 * errors (negative), normal errors are negated, while internal errors
692 * are all mapped to -EINTR, while showing a nice warning message. (jh)
693 *
694 */
695static int coda_upcall(struct coda_sb_info *sbi,
696 int inSize, int *outSize,
697 union inputArgs *buffer)
698{
699 struct venus_comm *vcommp;
700 union outputArgs *out;
701 struct upc_req *req;
702 int error = 0;
703
704 vcommp = sbi->sbi_vcomm;
705 if ( !vcommp->vc_inuse ) {
706 printk("No pseudo device in upcall comms at %p\n", vcommp);
707 return -ENXIO;
708 }
709
710 /* Format the request message. */
711 req = upc_alloc();
712 if (!req) {
713 printk("Failed to allocate upc_req structure\n");
714 return -ENOMEM;
715 }
716 req->uc_data = (void *)buffer;
717 req->uc_flags = 0;
718 req->uc_inSize = inSize;
719 req->uc_outSize = *outSize ? *outSize : inSize;
720 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
721 req->uc_unique = ++vcommp->vc_seq;
722 init_waitqueue_head(&req->uc_sleep);
723
724 /* Fill in the common input args. */
725 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
726
727 /* Append msg to pending queue and poke Venus. */
728 list_add(&(req->uc_chain), vcommp->vc_pending.prev);
729
730 wake_up_interruptible(&vcommp->vc_waitq);
731 /* We can be interrupted while we wait for Venus to process
732 * our request. If the interrupt occurs before Venus has read
733 * the request, we dequeue and return. If it occurs after the
734 * read but before the reply, we dequeue, send a signal
735 * message, and return. If it occurs after the reply we ignore
736 * it. In no case do we want to restart the syscall. If it
737 * was interrupted by a venus shutdown (psdev_close), return
738 * ENODEV. */
739
740 /* Go to sleep. Wake up on signals only after the timeout. */
741 coda_waitfor_upcall(req, vcommp);
742
743 if (vcommp->vc_inuse) { /* i.e. Venus is still alive */
744 /* Op went through, interrupt or not... */
745 if (req->uc_flags & REQ_WRITE) {
746 out = (union outputArgs *)req->uc_data;
747 /* here we map positive Venus errors to kernel errors */
748 error = -out->oh.result;
749 *outSize = req->uc_outSize;
750 goto exit;
751 }
752 if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) {
753 /* Interrupted before venus read it. */
754 list_del(&(req->uc_chain));
755 /* perhaps the best way to convince the app to
756 give up? */
757 error = -EINTR;
758 goto exit;
759 }
760 if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
761 /* interrupted after Venus did its read, send signal */
762 union inputArgs *sig_inputArgs;
763 struct upc_req *sig_req;
764
765 list_del(&(req->uc_chain));
766 error = -ENOMEM;
767 sig_req = upc_alloc();
768 if (!sig_req) goto exit;
769
770 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
771 if (!sig_req->uc_data) {
772 upc_free(sig_req);
773 goto exit;
774 }
775
776 error = -EINTR;
777 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
778 sig_inputArgs->ih.opcode = CODA_SIGNAL;
779 sig_inputArgs->ih.unique = req->uc_unique;
780
781 sig_req->uc_flags = REQ_ASYNC;
782 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
783 sig_req->uc_unique = sig_inputArgs->ih.unique;
784 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
785 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
786
787 /* insert at head of queue! */
788 list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
789 wake_up_interruptible(&vcommp->vc_waitq);
790 } else {
791 printk("Coda: Strange interruption..\n");
792 error = -EINTR;
793 }
794 } else { /* If venus died i.e. !VC_OPEN(vcommp) */
795 printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
796 req->uc_opcode, req->uc_unique, req->uc_flags);
797 error = -ENODEV;
798 }
799
800 exit:
801 upc_free(req);
802 return error;
803}
804
805/*
806 The statements below are part of the Coda opportunistic
807 programming -- taken from the Mach/BSD kernel code for Coda.
808 You don't get correct semantics by stating what needs to be
809 done without guaranteeing the invariants needed for it to happen.
810 When will be have time to find out what exactly is going on? (pjb)
811*/
812
813
814/*
815 * There are 7 cases where cache invalidations occur. The semantics
816 * of each is listed here:
817 *
818 * CODA_FLUSH -- flush all entries from the name cache and the cnode cache.
819 * CODA_PURGEUSER -- flush all entries from the name cache for a specific user
820 * This call is a result of token expiration.
821 *
822 * The next arise as the result of callbacks on a file or directory.
823 * CODA_ZAPFILE -- flush the cached attributes for a file.
824
825 * CODA_ZAPDIR -- flush the attributes for the dir and
826 * force a new lookup for all the children
827 of this dir.
828
829 *
830 * The next is a result of Venus detecting an inconsistent file.
831 * CODA_PURGEFID -- flush the attribute for the file
832 * purge it and its children from the dcache
833 *
834 * The last allows Venus to replace local fids with global ones
835 * during reintegration.
836 *
837 * CODA_REPLACE -- replace one CodaFid with another throughout the name cache */
838
839int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
840{
841 /* Handle invalidation requests. */
842 if ( !sb || !sb->s_root || !sb->s_root->d_inode)
843 return 0;
844
845 switch (opcode) {
846
847 case CODA_FLUSH : {
848 coda_cache_clear_all(sb);
849 shrink_dcache_sb(sb);
850 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
851 return(0);
852 }
853
854 case CODA_PURGEUSER : {
855 coda_cache_clear_all(sb);
856 return(0);
857 }
858
859 case CODA_ZAPDIR : {
860 struct inode *inode;
861 struct CodaFid *fid = &out->coda_zapdir.CodaFid;
862
863 inode = coda_fid_to_inode(fid, sb);
864 if (inode) {
865 coda_flag_inode_children(inode, C_PURGE);
866 coda_flag_inode(inode, C_VATTR);
867 iput(inode);
868 }
869
870 return(0);
871 }
872
873 case CODA_ZAPFILE : {
874 struct inode *inode;
875 struct CodaFid *fid = &out->coda_zapfile.CodaFid;
876 inode = coda_fid_to_inode(fid, sb);
877 if ( inode ) {
878 coda_flag_inode(inode, C_VATTR);
879 iput(inode);
880 }
881 return 0;
882 }
883
884 case CODA_PURGEFID : {
885 struct inode *inode;
886 struct CodaFid *fid = &out->coda_purgefid.CodaFid;
887 inode = coda_fid_to_inode(fid, sb);
888 if ( inode ) {
889 coda_flag_inode_children(inode, C_PURGE);
890
891 /* catch the dentries later if some are still busy */
892 coda_flag_inode(inode, C_PURGE);
893 d_prune_aliases(inode);
894
895 iput(inode);
896 }
897 return 0;
898 }
899
900 case CODA_REPLACE : {
901 struct inode *inode;
902 struct CodaFid *oldfid = &out->coda_replace.OldFid;
903 struct CodaFid *newfid = &out->coda_replace.NewFid;
904 inode = coda_fid_to_inode(oldfid, sb);
905 if ( inode ) {
906 coda_replace_fid(inode, oldfid, newfid);
907 iput(inode);
908 }
909 return 0;
910 }
911 }
912 return 0;
913}
914