aboutsummaryrefslogtreecommitdiffstats
path: root/fs/coda
diff options
context:
space:
mode:
Diffstat (limited to 'fs/coda')
-rw-r--r--fs/coda/cache.c7
-rw-r--r--fs/coda/cnode.c7
-rw-r--r--fs/coda/coda_int.h7
-rw-r--r--fs/coda/dir.c286
-rw-r--r--fs/coda/file.c17
-rw-r--r--fs/coda/inode.c46
-rw-r--r--fs/coda/psdev.c88
-rw-r--r--fs/coda/symlink.c2
-rw-r--r--fs/coda/sysctl.c228
-rw-r--r--fs/coda/upcall.c454
10 files changed, 447 insertions, 695 deletions
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index fcb88fa8d2f2..8a2370341c7a 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -43,17 +43,12 @@ void coda_cache_enter(struct inode *inode, int mask)
43void coda_cache_clear_inode(struct inode *inode) 43void coda_cache_clear_inode(struct inode *inode)
44{ 44{
45 struct coda_inode_info *cii = ITOC(inode); 45 struct coda_inode_info *cii = ITOC(inode);
46 cii->c_cached_perm = 0; 46 cii->c_cached_epoch = atomic_read(&permission_epoch) - 1;
47} 47}
48 48
49/* remove all acl caches */ 49/* remove all acl caches */
50void coda_cache_clear_all(struct super_block *sb) 50void coda_cache_clear_all(struct super_block *sb)
51{ 51{
52 struct coda_sb_info *sbi;
53
54 sbi = coda_sbp(sb);
55 BUG_ON(!sbi);
56
57 atomic_inc(&permission_epoch); 52 atomic_inc(&permission_epoch);
58} 53}
59 54
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index 28c872747f81..a7a780929eec 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -55,11 +55,6 @@ static int coda_set_inode(struct inode *inode, void *data)
55 return 0; 55 return 0;
56} 56}
57 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, 58struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
64 struct coda_vattr * attr) 59 struct coda_vattr * attr)
65{ 60{
@@ -141,7 +136,7 @@ struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
141 return NULL; 136 return NULL;
142 } 137 }
143 138
144 inode = iget5_locked(sb, hash, coda_test_inode, coda_fail_inode, fid); 139 inode = ilookup5(sb, hash, coda_test_inode, fid);
145 if ( !inode ) 140 if ( !inode )
146 return NULL; 141 return NULL;
147 142
diff --git a/fs/coda/coda_int.h b/fs/coda/coda_int.h
index 9e6338fea514..8ccd5ed81d9c 100644
--- a/fs/coda/coda_int.h
+++ b/fs/coda/coda_int.h
@@ -1,12 +1,19 @@
1#ifndef _CODA_INT_ 1#ifndef _CODA_INT_
2#define _CODA_INT_ 2#define _CODA_INT_
3 3
4struct dentry;
5
4extern struct file_system_type coda_fs_type; 6extern struct file_system_type coda_fs_type;
7extern unsigned long coda_timeout;
8extern int coda_hard;
9extern int coda_fake_statfs;
5 10
6void coda_destroy_inodecache(void); 11void coda_destroy_inodecache(void);
7int coda_init_inodecache(void); 12int coda_init_inodecache(void);
8int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, 13int coda_fsync(struct file *coda_file, struct dentry *coda_dentry,
9 int datasync); 14 int datasync);
15void coda_sysctl_init(void);
16void coda_sysctl_clean(void);
10 17
11#endif /* _CODA_INT_ */ 18#endif /* _CODA_INT_ */
12 19
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 898a86dde8f5..04a3dd84c993 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -25,7 +25,6 @@
25#include <linux/coda_psdev.h> 25#include <linux/coda_psdev.h>
26#include <linux/coda_fs_i.h> 26#include <linux/coda_fs_i.h>
27#include <linux/coda_cache.h> 27#include <linux/coda_cache.h>
28#include <linux/coda_proc.h>
29 28
30#include "coda_int.h" 29#include "coda_int.h"
31 30
@@ -43,15 +42,15 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
43 struct inode *new_inode, struct dentry *new_dentry); 42 struct inode *new_inode, struct dentry *new_dentry);
44 43
45/* dir file-ops */ 44/* dir file-ops */
46static int coda_readdir(struct file *file, void *dirent, filldir_t filldir); 45static int coda_readdir(struct file *file, void *buf, filldir_t filldir);
47 46
48/* dentry ops */ 47/* dentry ops */
49static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd); 48static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd);
50static int coda_dentry_delete(struct dentry *); 49static int coda_dentry_delete(struct dentry *);
51 50
52/* support routines */ 51/* support routines */
53static int coda_venus_readdir(struct file *filp, filldir_t filldir, 52static int coda_venus_readdir(struct file *coda_file, void *buf,
54 void *dirent, struct dentry *dir); 53 filldir_t filldir);
55 54
56/* same as fs/bad_inode.c */ 55/* same as fs/bad_inode.c */
57static int coda_return_EIO(void) 56static int coda_return_EIO(void)
@@ -97,58 +96,45 @@ const struct file_operations coda_dir_operations = {
97/* access routines: lookup, readlink, permission */ 96/* access routines: lookup, readlink, permission */
98static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) 97static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd)
99{ 98{
100 struct inode *res_inode = NULL; 99 struct inode *inode = NULL;
101 struct CodaFid resfid = { { 0, } }; 100 struct CodaFid resfid = { { 0, } };
102 int dropme = 0; /* to indicate entry should not be cached */
103 int type = 0; 101 int type = 0;
104 int error = 0; 102 int error = 0;
105 const char *name = entry->d_name.name; 103 const char *name = entry->d_name.name;
106 size_t length = entry->d_name.len; 104 size_t length = entry->d_name.len;
107 105
108 if ( length > CODA_MAXNAMLEN ) { 106 if (length > CODA_MAXNAMLEN) {
109 printk("name too long: lookup, %s (%*s)\n", 107 printk(KERN_ERR "name too long: lookup, %s (%*s)\n",
110 coda_i2s(dir), (int)length, name); 108 coda_i2s(dir), (int)length, name);
111 return ERR_PTR(-ENAMETOOLONG); 109 return ERR_PTR(-ENAMETOOLONG);
112 } 110 }
113 111
112 /* control object, create inode on the fly */
113 if (coda_isroot(dir) && coda_iscontrol(name, length)) {
114 error = coda_cnode_makectl(&inode, dir->i_sb);
115 type = CODA_NOCACHE;
116 goto exit;
117 }
118
114 lock_kernel(); 119 lock_kernel();
115 /* control object, create inode on the fly */
116 if (coda_isroot(dir) && coda_iscontrol(name, length)) {
117 error = coda_cnode_makectl(&res_inode, dir->i_sb);
118 dropme = 1;
119 goto exit;
120 }
121 120
122 error = venus_lookup(dir->i_sb, coda_i2f(dir), 121 error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length,
123 (const char *)name, length, &type, &resfid); 122 &type, &resfid);
123 if (!error)
124 error = coda_cnode_make(&inode, &resfid, dir->i_sb);
124 125
125 res_inode = NULL; 126 unlock_kernel();
126 if (!error) {
127 if (type & CODA_NOCACHE) {
128 type &= (~CODA_NOCACHE);
129 dropme = 1;
130 }
131 127
132 error = coda_cnode_make(&res_inode, &resfid, dir->i_sb); 128 if (error && error != -ENOENT)
133 if (error) {
134 unlock_kernel();
135 return ERR_PTR(error);
136 }
137 } else if (error != -ENOENT) {
138 unlock_kernel();
139 return ERR_PTR(error); 129 return ERR_PTR(error);
140 }
141 130
142exit: 131exit:
143 entry->d_time = 0;
144 entry->d_op = &coda_dentry_operations; 132 entry->d_op = &coda_dentry_operations;
145 d_add(entry, res_inode); 133
146 if ( dropme ) { 134 if (inode && (type & CODA_NOCACHE))
147 d_drop(entry); 135 coda_flag_inode(inode, C_VATTR | C_PURGE);
148 coda_flag_inode(res_inode, C_VATTR); 136
149 } 137 return d_splice_alias(inode, entry);
150 unlock_kernel();
151 return NULL;
152} 138}
153 139
154 140
@@ -161,8 +147,6 @@ int coda_permission(struct inode *inode, int mask, struct nameidata *nd)
161 147
162 lock_kernel(); 148 lock_kernel();
163 149
164 coda_vfs_stat.permission++;
165
166 if (coda_cache_check(inode, mask)) 150 if (coda_cache_check(inode, mask))
167 goto out; 151 goto out;
168 152
@@ -173,12 +157,11 @@ int coda_permission(struct inode *inode, int mask, struct nameidata *nd)
173 157
174 out: 158 out:
175 unlock_kernel(); 159 unlock_kernel();
176 160 return error;
177 return error;
178} 161}
179 162
180 163
181static inline void coda_dir_changed(struct inode *dir, int link) 164static inline void coda_dir_update_mtime(struct inode *dir)
182{ 165{
183#ifdef REQUERY_VENUS_FOR_MTIME 166#ifdef REQUERY_VENUS_FOR_MTIME
184 /* invalidate the directory cnode's attributes so we refetch the 167 /* invalidate the directory cnode's attributes so we refetch the
@@ -186,12 +169,27 @@ static inline void coda_dir_changed(struct inode *dir, int link)
186 coda_flag_inode(dir, C_VATTR); 169 coda_flag_inode(dir, C_VATTR);
187#else 170#else
188 /* optimistically we can also act as if our nose bleeds. The 171 /* optimistically we can also act as if our nose bleeds. The
189 * granularity of the mtime is coarse anyways so we might actually be 172 * granularity of the mtime is coarse anyways so we might actually be
190 * right most of the time. Note: we only do this for directories. */ 173 * right most of the time. Note: we only do this for directories. */
191 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 174 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
192#endif 175#endif
193 if (link) 176}
194 dir->i_nlink += link; 177
178/* we have to wrap inc_nlink/drop_nlink because sometimes userspace uses a
179 * trick to fool GNU find's optimizations. If we can't be sure of the link
180 * (because of volume mount points) we set i_nlink to 1 which forces find
181 * to consider every child as a possible directory. We should also never
182 * see an increment or decrement for deleted directories where i_nlink == 0 */
183static inline void coda_dir_inc_nlink(struct inode *dir)
184{
185 if (dir->i_nlink >= 2)
186 inc_nlink(dir);
187}
188
189static inline void coda_dir_drop_nlink(struct inode *dir)
190{
191 if (dir->i_nlink > 2)
192 drop_nlink(dir);
195} 193}
196 194
197/* creation routines: create, mknod, mkdir, link, symlink */ 195/* creation routines: create, mknod, mkdir, link, symlink */
@@ -205,7 +203,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode, struct na
205 struct coda_vattr attrs; 203 struct coda_vattr attrs;
206 204
207 lock_kernel(); 205 lock_kernel();
208 coda_vfs_stat.create++;
209 206
210 if (coda_isroot(dir) && coda_iscontrol(name, length)) { 207 if (coda_isroot(dir) && coda_iscontrol(name, length)) {
211 unlock_kernel(); 208 unlock_kernel();
@@ -229,10 +226,10 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode, struct na
229 } 226 }
230 227
231 /* invalidate the directory cnode's attributes */ 228 /* invalidate the directory cnode's attributes */
232 coda_dir_changed(dir, 0); 229 coda_dir_update_mtime(dir);
233 unlock_kernel(); 230 unlock_kernel();
234 d_instantiate(de, inode); 231 d_instantiate(de, inode);
235 return 0; 232 return 0;
236} 233}
237 234
238static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) 235static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
@@ -245,7 +242,6 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
245 struct CodaFid newfid; 242 struct CodaFid newfid;
246 243
247 lock_kernel(); 244 lock_kernel();
248 coda_vfs_stat.mkdir++;
249 245
250 if (coda_isroot(dir) && coda_iscontrol(name, len)) { 246 if (coda_isroot(dir) && coda_iscontrol(name, len)) {
251 unlock_kernel(); 247 unlock_kernel();
@@ -268,12 +264,13 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
268 d_drop(de); 264 d_drop(de);
269 return PTR_ERR(inode); 265 return PTR_ERR(inode);
270 } 266 }
271 267
272 /* invalidate the directory cnode's attributes */ 268 /* invalidate the directory cnode's attributes */
273 coda_dir_changed(dir, 1); 269 coda_dir_inc_nlink(dir);
270 coda_dir_update_mtime(dir);
274 unlock_kernel(); 271 unlock_kernel();
275 d_instantiate(de, inode); 272 d_instantiate(de, inode);
276 return 0; 273 return 0;
277} 274}
278 275
279/* try to make de an entry in dir_inodde linked to source_de */ 276/* try to make de an entry in dir_inodde linked to source_de */
@@ -286,7 +283,6 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
286 int error; 283 int error;
287 284
288 lock_kernel(); 285 lock_kernel();
289 coda_vfs_stat.link++;
290 286
291 if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) { 287 if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
292 unlock_kernel(); 288 unlock_kernel();
@@ -296,16 +292,16 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
296 error = venus_link(dir_inode->i_sb, coda_i2f(inode), 292 error = venus_link(dir_inode->i_sb, coda_i2f(inode),
297 coda_i2f(dir_inode), (const char *)name, len); 293 coda_i2f(dir_inode), (const char *)name, len);
298 294
299 if (error) { 295 if (error) {
300 d_drop(de); 296 d_drop(de);
301 goto out; 297 goto out;
302 } 298 }
303 299
304 coda_dir_changed(dir_inode, 0); 300 coda_dir_update_mtime(dir_inode);
305 atomic_inc(&inode->i_count); 301 atomic_inc(&inode->i_count);
306 d_instantiate(de, inode); 302 d_instantiate(de, inode);
307 inc_nlink(inode); 303 inc_nlink(inode);
308 304
309out: 305out:
310 unlock_kernel(); 306 unlock_kernel();
311 return(error); 307 return(error);
@@ -318,10 +314,9 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
318 const char *name = de->d_name.name; 314 const char *name = de->d_name.name;
319 int len = de->d_name.len; 315 int len = de->d_name.len;
320 int symlen; 316 int symlen;
321 int error=0; 317 int error = 0;
322 318
323 lock_kernel(); 319 lock_kernel();
324 coda_vfs_stat.symlink++;
325 320
326 if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) { 321 if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
327 unlock_kernel(); 322 unlock_kernel();
@@ -336,18 +331,18 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
336 331
337 /* 332 /*
338 * This entry is now negative. Since we do not create 333 * This entry is now negative. Since we do not create
339 * an inode for the entry we have to drop it. 334 * an inode for the entry we have to drop it.
340 */ 335 */
341 d_drop(de); 336 d_drop(de);
342 error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len, 337 error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len,
343 symname, symlen); 338 symname, symlen);
344 339
345 /* mtime is no good anymore */ 340 /* mtime is no good anymore */
346 if ( !error ) 341 if ( !error )
347 coda_dir_changed(dir_inode, 0); 342 coda_dir_update_mtime(dir_inode);
348 343
349 unlock_kernel(); 344 unlock_kernel();
350 return error; 345 return error;
351} 346}
352 347
353/* destruction routines: unlink, rmdir */ 348/* destruction routines: unlink, rmdir */
@@ -358,79 +353,70 @@ int coda_unlink(struct inode *dir, struct dentry *de)
358 int len = de->d_name.len; 353 int len = de->d_name.len;
359 354
360 lock_kernel(); 355 lock_kernel();
361 coda_vfs_stat.unlink++;
362 356
363 error = venus_remove(dir->i_sb, coda_i2f(dir), name, len); 357 error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
364 if ( error ) { 358 if ( error ) {
365 unlock_kernel(); 359 unlock_kernel();
366 return error; 360 return error;
367 } 361 }
368 362
369 coda_dir_changed(dir, 0); 363 coda_dir_update_mtime(dir);
370 drop_nlink(de->d_inode); 364 drop_nlink(de->d_inode);
371 unlock_kernel(); 365 unlock_kernel();
372 366 return 0;
373 return 0;
374} 367}
375 368
376int coda_rmdir(struct inode *dir, struct dentry *de) 369int coda_rmdir(struct inode *dir, struct dentry *de)
377{ 370{
378 const char *name = de->d_name.name; 371 const char *name = de->d_name.name;
379 int len = de->d_name.len; 372 int len = de->d_name.len;
380 int error; 373 int error;
381 374
382 lock_kernel(); 375 lock_kernel();
383 coda_vfs_stat.rmdir++;
384 376
385 if (!d_unhashed(de)) {
386 unlock_kernel();
387 return -EBUSY;
388 }
389 error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len); 377 error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
378 if (!error) {
379 /* VFS may delete the child */
380 if (de->d_inode)
381 de->d_inode->i_nlink = 0;
390 382
391 if ( error ) { 383 /* fix the link count of the parent */
392 unlock_kernel(); 384 coda_dir_drop_nlink(dir);
393 return error; 385 coda_dir_update_mtime(dir);
394 } 386 }
395
396 coda_dir_changed(dir, -1);
397 drop_nlink(de->d_inode);
398 d_delete(de);
399 unlock_kernel(); 387 unlock_kernel();
400 388 return error;
401 return 0;
402} 389}
403 390
404/* rename */ 391/* rename */
405static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, 392static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
406 struct inode *new_dir, struct dentry *new_dentry) 393 struct inode *new_dir, struct dentry *new_dentry)
407{ 394{
408 const char *old_name = old_dentry->d_name.name; 395 const char *old_name = old_dentry->d_name.name;
409 const char *new_name = new_dentry->d_name.name; 396 const char *new_name = new_dentry->d_name.name;
410 int old_length = old_dentry->d_name.len; 397 int old_length = old_dentry->d_name.len;
411 int new_length = new_dentry->d_name.len; 398 int new_length = new_dentry->d_name.len;
412 int link_adjust = 0; 399 int error;
413 int error;
414 400
415 lock_kernel(); 401 lock_kernel();
416 coda_vfs_stat.rename++;
417 402
418 error = venus_rename(old_dir->i_sb, coda_i2f(old_dir), 403 error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
419 coda_i2f(new_dir), old_length, new_length, 404 coda_i2f(new_dir), old_length, new_length,
420 (const char *) old_name, (const char *)new_name); 405 (const char *) old_name, (const char *)new_name);
421 406
422 if ( !error ) { 407 if ( !error ) {
423 if ( new_dentry->d_inode ) { 408 if ( new_dentry->d_inode ) {
424 if ( S_ISDIR(new_dentry->d_inode->i_mode) ) 409 if ( S_ISDIR(new_dentry->d_inode->i_mode) ) {
425 link_adjust = 1; 410 coda_dir_drop_nlink(old_dir);
426 411 coda_dir_inc_nlink(new_dir);
427 coda_dir_changed(old_dir, -link_adjust); 412 }
428 coda_dir_changed(new_dir, link_adjust); 413 coda_dir_update_mtime(old_dir);
414 coda_dir_update_mtime(new_dir);
429 coda_flag_inode(new_dentry->d_inode, C_VATTR); 415 coda_flag_inode(new_dentry->d_inode, C_VATTR);
430 } else { 416 } else {
431 coda_flag_inode(old_dir, C_VATTR); 417 coda_flag_inode(old_dir, C_VATTR);
432 coda_flag_inode(new_dir, C_VATTR); 418 coda_flag_inode(new_dir, C_VATTR);
433 } 419 }
434 } 420 }
435 unlock_kernel(); 421 unlock_kernel();
436 422
@@ -439,44 +425,41 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
439 425
440 426
441/* file operations for directories */ 427/* file operations for directories */
442int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir) 428int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
443{ 429{
444 struct dentry *coda_dentry = coda_file->f_path.dentry;
445 struct coda_file_info *cfi; 430 struct coda_file_info *cfi;
446 struct file *host_file; 431 struct file *host_file;
447 struct inode *host_inode;
448 int ret; 432 int ret;
449 433
450 cfi = CODA_FTOC(coda_file); 434 cfi = CODA_FTOC(coda_file);
451 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 435 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
452 host_file = cfi->cfi_container; 436 host_file = cfi->cfi_container;
453 437
454 coda_vfs_stat.readdir++; 438 if (!host_file->f_op)
439 return -ENOTDIR;
455 440
456 host_inode = host_file->f_path.dentry->d_inode; 441 if (host_file->f_op->readdir)
457 mutex_lock(&host_inode->i_mutex); 442 {
458 host_file->f_pos = coda_file->f_pos; 443 /* potemkin case: we were handed a directory inode.
444 * We can't use vfs_readdir because we have to keep the file
445 * position in sync between the coda_file and the host_file.
446 * and as such we need grab the inode mutex. */
447 struct inode *host_inode = host_file->f_path.dentry->d_inode;
459 448
460 if (!host_file->f_op->readdir) { 449 mutex_lock(&host_inode->i_mutex);
461 /* Venus: we must read Venus dirents from the file */ 450 host_file->f_pos = coda_file->f_pos;
462 ret = coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
463 } else {
464 /* potemkin case: we were handed a directory inode. */
465 /* Yuk, we can't call vfs_readdir because we are already
466 * holding the inode semaphore. */
467 ret = -ENOTDIR;
468 if (!host_file->f_op || !host_file->f_op->readdir)
469 goto out;
470 451
471 ret = -ENOENT; 452 ret = -ENOENT;
472 if (!IS_DEADDIR(host_inode)) { 453 if (!IS_DEADDIR(host_inode)) {
473 ret = host_file->f_op->readdir(host_file, dirent, filldir); 454 ret = host_file->f_op->readdir(host_file, buf, filldir);
474 file_accessed(host_file); 455 file_accessed(host_file);
475 } 456 }
457
458 coda_file->f_pos = host_file->f_pos;
459 mutex_unlock(&host_inode->i_mutex);
476 } 460 }
477out: 461 else /* Venus: we must read Venus dirents from a file */
478 coda_file->f_pos = host_file->f_pos; 462 ret = coda_venus_readdir(coda_file, buf, filldir);
479 mutex_unlock(&host_inode->i_mutex);
480 463
481 return ret; 464 return ret;
482} 465}
@@ -501,57 +484,68 @@ static inline unsigned int CDT2DT(unsigned char cdt)
501} 484}
502 485
503/* support routines */ 486/* support routines */
504static int coda_venus_readdir(struct file *filp, filldir_t filldir, 487static int coda_venus_readdir(struct file *coda_file, void *buf,
505 void *dirent, struct dentry *dir) 488 filldir_t filldir)
506{ 489{
507 int result = 0; /* # of entries returned */ 490 int result = 0; /* # of entries returned */
491 struct coda_file_info *cfi;
492 struct coda_inode_info *cii;
493 struct file *host_file;
494 struct dentry *de;
508 struct venus_dirent *vdir; 495 struct venus_dirent *vdir;
509 unsigned long vdir_size = 496 unsigned long vdir_size =
510 (unsigned long)(&((struct venus_dirent *)0)->d_name); 497 (unsigned long)(&((struct venus_dirent *)0)->d_name);
511 unsigned int type; 498 unsigned int type;
512 struct qstr name; 499 struct qstr name;
513 ino_t ino; 500 ino_t ino;
514 int ret, i; 501 int ret;
502
503 cfi = CODA_FTOC(coda_file);
504 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
505 host_file = cfi->cfi_container;
506
507 de = coda_file->f_path.dentry;
508 cii = ITOC(de->d_inode);
515 509
516 vdir = kmalloc(sizeof(*vdir), GFP_KERNEL); 510 vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
517 if (!vdir) return -ENOMEM; 511 if (!vdir) return -ENOMEM;
518 512
519 i = filp->f_pos; 513 switch (coda_file->f_pos) {
520 switch(i) {
521 case 0: 514 case 0:
522 ret = filldir(dirent, ".", 1, 0, dir->d_inode->i_ino, DT_DIR); 515 ret = filldir(buf, ".", 1, 0, de->d_inode->i_ino, DT_DIR);
523 if (ret < 0) break; 516 if (ret < 0) break;
524 result++; 517 result++;
525 filp->f_pos++; 518 coda_file->f_pos++;
526 /* fallthrough */ 519 /* fallthrough */
527 case 1: 520 case 1:
528 ret = filldir(dirent, "..", 2, 1, dir->d_parent->d_inode->i_ino, DT_DIR); 521 ret = filldir(buf, "..", 2, 1, de->d_parent->d_inode->i_ino, DT_DIR);
529 if (ret < 0) break; 522 if (ret < 0) break;
530 result++; 523 result++;
531 filp->f_pos++; 524 coda_file->f_pos++;
532 /* fallthrough */ 525 /* fallthrough */
533 default: 526 default:
534 while (1) { 527 while (1) {
535 /* read entries from the directory file */ 528 /* read entries from the directory file */
536 ret = kernel_read(filp, filp->f_pos - 2, (char *)vdir, 529 ret = kernel_read(host_file, coda_file->f_pos - 2, (char *)vdir,
537 sizeof(*vdir)); 530 sizeof(*vdir));
538 if (ret < 0) { 531 if (ret < 0) {
539 printk("coda_venus_readdir: read dir failed %d\n", ret); 532 printk(KERN_ERR "coda readdir: read dir %s failed %d\n",
533 coda_f2s(&cii->c_fid), ret);
540 break; 534 break;
541 } 535 }
542 if (ret == 0) break; /* end of directory file reached */ 536 if (ret == 0) break; /* end of directory file reached */
543 537
544 /* catch truncated reads */ 538 /* catch truncated reads */
545 if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) { 539 if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
546 printk("coda_venus_readdir: short read: %ld\n", 540 printk(KERN_ERR "coda readdir: short read on %s\n",
547 filp->f_path.dentry->d_inode->i_ino); 541 coda_f2s(&cii->c_fid));
548 ret = -EBADF; 542 ret = -EBADF;
549 break; 543 break;
550 } 544 }
551 /* validate whether the directory file actually makes sense */ 545 /* validate whether the directory file actually makes sense */
552 if (vdir->d_reclen < vdir_size + vdir->d_namlen) { 546 if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
553 printk("coda_venus_readdir: Invalid dir: %ld\n", 547 printk(KERN_ERR "coda readdir: invalid dir %s\n",
554 filp->f_path.dentry->d_inode->i_ino); 548 coda_f2s(&cii->c_fid));
555 ret = -EBADF; 549 ret = -EBADF;
556 break; 550 break;
557 } 551 }
@@ -570,21 +564,21 @@ static int coda_venus_readdir(struct file *filp, filldir_t filldir,
570 * userspace doesn't have to worry about breaking 564 * userspace doesn't have to worry about breaking
571 * getcwd by having mismatched inode numbers for 565 * getcwd by having mismatched inode numbers for
572 * internal volume mountpoints. */ 566 * internal volume mountpoints. */
573 ino = find_inode_number(dir, &name); 567 ino = find_inode_number(de, &name);
574 if (!ino) ino = vdir->d_fileno; 568 if (!ino) ino = vdir->d_fileno;
575 569
576 type = CDT2DT(vdir->d_type); 570 type = CDT2DT(vdir->d_type);
577 ret = filldir(dirent, name.name, name.len, filp->f_pos, 571 ret = filldir(buf, name.name, name.len,
578 ino, type); 572 coda_file->f_pos, ino, type);
579 /* failure means no space for filling in this round */ 573 /* failure means no space for filling in this round */
580 if (ret < 0) break; 574 if (ret < 0) break;
581 result++; 575 result++;
582 } 576 }
583 /* we'll always have progress because d_reclen is unsigned and 577 /* we'll always have progress because d_reclen is unsigned and
584 * we've already established it is non-zero. */ 578 * we've already established it is non-zero. */
585 filp->f_pos += vdir->d_reclen; 579 coda_file->f_pos += vdir->d_reclen;
580 }
586 } 581 }
587 }
588 kfree(vdir); 582 kfree(vdir);
589 return result ? result : ret; 583 return result ? result : ret;
590} 584}
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 99dbe866816d..7594962604c2 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -22,7 +22,6 @@
22#include <linux/coda_linux.h> 22#include <linux/coda_linux.h>
23#include <linux/coda_fs_i.h> 23#include <linux/coda_fs_i.h>
24#include <linux/coda_psdev.h> 24#include <linux/coda_psdev.h>
25#include <linux/coda_proc.h>
26 25
27#include "coda_int.h" 26#include "coda_int.h"
28 27
@@ -134,8 +133,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
134 unsigned short coda_flags = coda_flags_to_cflags(flags); 133 unsigned short coda_flags = coda_flags_to_cflags(flags);
135 struct coda_file_info *cfi; 134 struct coda_file_info *cfi;
136 135
137 coda_vfs_stat.open++;
138
139 cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL); 136 cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL);
140 if (!cfi) 137 if (!cfi)
141 return -ENOMEM; 138 return -ENOMEM;
@@ -143,8 +140,11 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
143 lock_kernel(); 140 lock_kernel();
144 141
145 error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags, 142 error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
146 &host_file); 143 &host_file);
147 if (error || !host_file) { 144 if (!host_file)
145 error = -EIO;
146
147 if (error) {
148 kfree(cfi); 148 kfree(cfi);
149 unlock_kernel(); 149 unlock_kernel();
150 return error; 150 return error;
@@ -173,8 +173,6 @@ int coda_flush(struct file *coda_file, fl_owner_t id)
173 173
174 lock_kernel(); 174 lock_kernel();
175 175
176 coda_vfs_stat.flush++;
177
178 /* last close semantics */ 176 /* last close semantics */
179 fcnt = file_count(coda_file); 177 fcnt = file_count(coda_file);
180 if (fcnt > 1) 178 if (fcnt > 1)
@@ -216,8 +214,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
216 int err = 0; 214 int err = 0;
217 215
218 lock_kernel(); 216 lock_kernel();
219 coda_vfs_stat.release++; 217
220
221 if (!use_coda_close) { 218 if (!use_coda_close) {
222 err = venus_release(coda_inode->i_sb, coda_i2f(coda_inode), 219 err = venus_release(coda_inode->i_sb, coda_i2f(coda_inode),
223 coda_flags); 220 coda_flags);
@@ -268,8 +265,6 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
268 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 265 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
269 host_file = cfi->cfi_container; 266 host_file = cfi->cfi_container;
270 267
271 coda_vfs_stat.fsync++;
272
273 if (host_file->f_op && host_file->f_op->fsync) { 268 if (host_file->f_op && host_file->f_op->fsync) {
274 host_dentry = host_file->f_path.dentry; 269 host_dentry = host_file->f_path.dentry;
275 host_inode = host_dentry->d_inode; 270 host_inode = host_dentry->d_inode;
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index dbff1bd4fb96..6771a4271e33 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -83,7 +83,7 @@ void coda_destroy_inodecache(void)
83 83
84static int coda_remount(struct super_block *sb, int *flags, char *data) 84static int coda_remount(struct super_block *sb, int *flags, char *data)
85{ 85{
86 *flags |= MS_NODIRATIME; 86 *flags |= MS_NOATIME;
87 return 0; 87 return 0;
88} 88}
89 89
@@ -141,11 +141,10 @@ static int get_device_index(struct coda_mount_data *data)
141 141
142static int coda_fill_super(struct super_block *sb, void *data, int silent) 142static int coda_fill_super(struct super_block *sb, void *data, int silent)
143{ 143{
144 struct inode *root = NULL; 144 struct inode *root = NULL;
145 struct coda_sb_info *sbi = NULL;
146 struct venus_comm *vc = NULL; 145 struct venus_comm *vc = NULL;
147 struct CodaFid fid; 146 struct CodaFid fid;
148 int error; 147 int error;
149 int idx; 148 int idx;
150 149
151 idx = get_device_index((struct coda_mount_data *) data); 150 idx = get_device_index((struct coda_mount_data *) data);
@@ -167,21 +166,14 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
167 return -EBUSY; 166 return -EBUSY;
168 } 167 }
169 168
170 sbi = kmalloc(sizeof(struct coda_sb_info), GFP_KERNEL);
171 if(!sbi) {
172 return -ENOMEM;
173 }
174
175 vc->vc_sb = sb; 169 vc->vc_sb = sb;
176 170
177 sbi->sbi_vcomm = vc; 171 sb->s_fs_info = vc;
178 172 sb->s_flags |= MS_NOATIME;
179 sb->s_fs_info = sbi; 173 sb->s_blocksize = 4096; /* XXXXX what do we put here?? */
180 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */ 174 sb->s_blocksize_bits = 12;
181 sb->s_blocksize = 1024; /* XXXXX what do we put here?? */ 175 sb->s_magic = CODA_SUPER_MAGIC;
182 sb->s_blocksize_bits = 10; 176 sb->s_op = &coda_super_operations;
183 sb->s_magic = CODA_SUPER_MAGIC;
184 sb->s_op = &coda_super_operations;
185 177
186 /* get root fid from Venus: this needs the root inode */ 178 /* get root fid from Venus: this needs the root inode */
187 error = venus_rootfid(sb, &fid); 179 error = venus_rootfid(sb, &fid);
@@ -207,26 +199,20 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
207 return 0; 199 return 0;
208 200
209 error: 201 error:
210 if (sbi) {
211 kfree(sbi);
212 if(vc)
213 vc->vc_sb = NULL;
214 }
215 if (root) 202 if (root)
216 iput(root); 203 iput(root);
204 if (vc)
205 vc->vc_sb = NULL;
217 206
218 return -EINVAL; 207 return -EINVAL;
219} 208}
220 209
221static void coda_put_super(struct super_block *sb) 210static void coda_put_super(struct super_block *sb)
222{ 211{
223 struct coda_sb_info *sbi; 212 coda_vcp(sb)->vc_sb = NULL;
224 213 sb->s_fs_info = NULL;
225 sbi = coda_sbp(sb);
226 sbi->sbi_vcomm->vc_sb = NULL;
227 214
228 printk("Coda: Bye bye.\n"); 215 printk("Coda: Bye bye.\n");
229 kfree(sbi);
230} 216}
231 217
232static void coda_clear_inode(struct inode *inode) 218static void coda_clear_inode(struct inode *inode)
@@ -296,7 +282,7 @@ static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)
296 282
297 /* and fill in the rest */ 283 /* and fill in the rest */
298 buf->f_type = CODA_SUPER_MAGIC; 284 buf->f_type = CODA_SUPER_MAGIC;
299 buf->f_bsize = 1024; 285 buf->f_bsize = 4096;
300 buf->f_namelen = CODA_MAXNAMLEN; 286 buf->f_namelen = CODA_MAXNAMLEN;
301 287
302 return 0; 288 return 0;
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 803aacf0d49c..dcc6aead70f5 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -45,12 +45,9 @@
45#include <linux/coda_linux.h> 45#include <linux/coda_linux.h>
46#include <linux/coda_fs_i.h> 46#include <linux/coda_fs_i.h>
47#include <linux/coda_psdev.h> 47#include <linux/coda_psdev.h>
48#include <linux/coda_proc.h>
49 48
50#include "coda_int.h" 49#include "coda_int.h"
51 50
52#define upc_free(r) kfree(r)
53
54/* statistics */ 51/* statistics */
55int coda_hard; /* allows signals during upcalls */ 52int coda_hard; /* allows signals during upcalls */
56unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */ 53unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */
@@ -195,7 +192,8 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
195 if (req->uc_opcode == CODA_OPEN_BY_FD) { 192 if (req->uc_opcode == CODA_OPEN_BY_FD) {
196 struct coda_open_by_fd_out *outp = 193 struct coda_open_by_fd_out *outp =
197 (struct coda_open_by_fd_out *)req->uc_data; 194 (struct coda_open_by_fd_out *)req->uc_data;
198 outp->fh = fget(outp->fd); 195 if (!outp->oh.result)
196 outp->fh = fget(outp->fd);
199 } 197 }
200 198
201 wake_up(&req->uc_sleep); 199 wake_up(&req->uc_sleep);
@@ -263,7 +261,7 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
263 } 261 }
264 262
265 CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr)); 263 CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
266 upc_free(req); 264 kfree(req);
267out: 265out:
268 unlock_kernel(); 266 unlock_kernel();
269 return (count ? count : retval); 267 return (count ? count : retval);
@@ -271,71 +269,70 @@ out:
271 269
272static int coda_psdev_open(struct inode * inode, struct file * file) 270static int coda_psdev_open(struct inode * inode, struct file * file)
273{ 271{
274 struct venus_comm *vcp; 272 struct venus_comm *vcp;
275 int idx; 273 int idx, err;
276 274
277 lock_kernel();
278 idx = iminor(inode); 275 idx = iminor(inode);
279 if(idx >= MAX_CODADEVS) { 276 if (idx < 0 || idx >= MAX_CODADEVS)
280 unlock_kernel();
281 return -ENODEV; 277 return -ENODEV;
282 }
283 278
279 lock_kernel();
280
281 err = -EBUSY;
284 vcp = &coda_comms[idx]; 282 vcp = &coda_comms[idx];
285 if(vcp->vc_inuse) { 283 if (!vcp->vc_inuse) {
286 unlock_kernel(); 284 vcp->vc_inuse++;
287 return -EBUSY; 285
288 }
289
290 if (!vcp->vc_inuse++) {
291 INIT_LIST_HEAD(&vcp->vc_pending); 286 INIT_LIST_HEAD(&vcp->vc_pending);
292 INIT_LIST_HEAD(&vcp->vc_processing); 287 INIT_LIST_HEAD(&vcp->vc_processing);
293 init_waitqueue_head(&vcp->vc_waitq); 288 init_waitqueue_head(&vcp->vc_waitq);
294 vcp->vc_sb = NULL; 289 vcp->vc_sb = NULL;
295 vcp->vc_seq = 0; 290 vcp->vc_seq = 0;
291
292 file->private_data = vcp;
293 err = 0;
296 } 294 }
297
298 file->private_data = vcp;
299 295
300 unlock_kernel(); 296 unlock_kernel();
301 return 0; 297 return err;
302} 298}
303 299
304 300
305static int coda_psdev_release(struct inode * inode, struct file * file) 301static int coda_psdev_release(struct inode * inode, struct file * file)
306{ 302{
307 struct venus_comm *vcp = (struct venus_comm *) file->private_data; 303 struct venus_comm *vcp = (struct venus_comm *) file->private_data;
308 struct upc_req *req, *tmp; 304 struct upc_req *req, *tmp;
309 305
310 lock_kernel(); 306 if (!vcp || !vcp->vc_inuse ) {
311 if ( !vcp->vc_inuse ) {
312 unlock_kernel();
313 printk("psdev_release: Not open.\n"); 307 printk("psdev_release: Not open.\n");
314 return -1; 308 return -1;
315 } 309 }
316 310
317 if (--vcp->vc_inuse) { 311 lock_kernel();
318 unlock_kernel(); 312
319 return 0; 313 /* Wakeup clients so they can return. */
320 }
321
322 /* Wakeup clients so they can return. */
323 list_for_each_entry_safe(req, tmp, &vcp->vc_pending, uc_chain) { 314 list_for_each_entry_safe(req, tmp, &vcp->vc_pending, uc_chain) {
315 list_del(&req->uc_chain);
316
324 /* Async requests need to be freed here */ 317 /* Async requests need to be freed here */
325 if (req->uc_flags & REQ_ASYNC) { 318 if (req->uc_flags & REQ_ASYNC) {
326 CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr)); 319 CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
327 upc_free(req); 320 kfree(req);
328 continue; 321 continue;
329 } 322 }
330 req->uc_flags |= REQ_ABORT; 323 req->uc_flags |= REQ_ABORT;
331 wake_up(&req->uc_sleep); 324 wake_up(&req->uc_sleep);
332 } 325 }
333 326
334 list_for_each_entry(req, &vcp->vc_processing, uc_chain) { 327 list_for_each_entry_safe(req, tmp, &vcp->vc_processing, uc_chain) {
328 list_del(&req->uc_chain);
329
335 req->uc_flags |= REQ_ABORT; 330 req->uc_flags |= REQ_ABORT;
336 wake_up(&req->uc_sleep); 331 wake_up(&req->uc_sleep);
337 } 332 }
338 333
334 file->private_data = NULL;
335 vcp->vc_inuse--;
339 unlock_kernel(); 336 unlock_kernel();
340 return 0; 337 return 0;
341} 338}
@@ -376,21 +373,20 @@ out:
376 return err; 373 return err;
377} 374}
378 375
379 376MODULE_AUTHOR("Jan Harkes, Peter J. Braam");
380MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>"); 377MODULE_DESCRIPTION("Coda Distributed File System VFS interface");
378MODULE_ALIAS_CHARDEV_MAJOR(CODA_PSDEV_MAJOR);
381MODULE_LICENSE("GPL"); 379MODULE_LICENSE("GPL");
380#ifdef CONFIG_CODA_FS_OLD_API
381MODULE_VERSION("5.3.21");
382#else
383MODULE_VERSION("6.6");
384#endif
382 385
383static int __init init_coda(void) 386static int __init init_coda(void)
384{ 387{
385 int status; 388 int status;
386 int i; 389 int i;
387 printk(KERN_INFO "Coda Kernel/Venus communications, "
388#ifdef CONFIG_CODA_FS_OLD_API
389 "v5.3.20"
390#else
391 "v6.0.0"
392#endif
393 ", coda@cs.cmu.edu\n");
394 390
395 status = coda_init_inodecache(); 391 status = coda_init_inodecache();
396 if (status) 392 if (status)
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
index 76e00a65a75b..4513b7258458 100644
--- a/fs/coda/symlink.c
+++ b/fs/coda/symlink.c
@@ -20,7 +20,6 @@
20#include <linux/coda_linux.h> 20#include <linux/coda_linux.h>
21#include <linux/coda_psdev.h> 21#include <linux/coda_psdev.h>
22#include <linux/coda_fs_i.h> 22#include <linux/coda_fs_i.h>
23#include <linux/coda_proc.h>
24 23
25static int coda_symlink_filler(struct file *file, struct page *page) 24static int coda_symlink_filler(struct file *file, struct page *page)
26{ 25{
@@ -32,7 +31,6 @@ static int coda_symlink_filler(struct file *file, struct page *page)
32 31
33 lock_kernel(); 32 lock_kernel();
34 cii = ITOC(inode); 33 cii = ITOC(inode);
35 coda_vfs_stat.follow_link++;
36 34
37 error = venus_readlink(inode->i_sb, &cii->c_fid, p, &len); 35 error = venus_readlink(inode->i_sb, &cii->c_fid, p, &len);
38 unlock_kernel(); 36 unlock_kernel();
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c
index c57a1fa7cf23..81b7771c6465 100644
--- a/fs/coda/sysctl.c
+++ b/fs/coda/sysctl.c
@@ -5,181 +5,14 @@
5 * 5 *
6 * Carnegie Mellon encourages users to contribute improvements to 6 * Carnegie Mellon encourages users to contribute improvements to
7 * the Coda project. Contact Peter Braam (coda@cs.cmu.edu). 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 */ 8 */
13 9
14#include <linux/time.h>
15#include <linux/mm.h>
16#include <linux/sysctl.h> 10#include <linux/sysctl.h>
17#include <linux/proc_fs.h>
18#include <linux/seq_file.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 11
27#include <linux/coda.h> 12#include "coda_int.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 13
34static struct ctl_table_header *fs_table_header; 14static struct ctl_table_header *fs_table_header;
35 15
36#define CODA_TIMEOUT 3 /* timeout on upcalls to become intrble */
37#define CODA_HARD 5 /* mount type "hard" or "soft" */
38#define CODA_VFS 6 /* vfs statistics */
39#define CODA_CACHE_INV 9 /* cache invalidation statistics */
40#define CODA_FAKE_STATFS 10 /* don't query venus for actual cache usage */
41
42struct coda_vfs_stats coda_vfs_stat;
43static struct coda_cache_inv_stats coda_cache_inv_stat;
44
45static void reset_coda_vfs_stats( void )
46{
47 memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
48}
49
50static void reset_coda_cache_inv_stats( void )
51{
52 memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
53}
54
55static int do_reset_coda_vfs_stats( ctl_table * table, int write,
56 struct file * filp, void __user * buffer,
57 size_t * lenp, loff_t * ppos )
58{
59 if ( write ) {
60 reset_coda_vfs_stats();
61
62 *ppos += *lenp;
63 } else {
64 *lenp = 0;
65 }
66
67 return 0;
68}
69
70static int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
71 struct file * filp,
72 void __user * buffer,
73 size_t * lenp, loff_t * ppos )
74{
75 if ( write ) {
76 reset_coda_cache_inv_stats();
77
78 *ppos += *lenp;
79 } else {
80 *lenp = 0;
81 }
82
83 return 0;
84}
85
86static int proc_vfs_stats_show(struct seq_file *m, void *v)
87{
88 struct coda_vfs_stats * ps = & coda_vfs_stat;
89
90 seq_printf(m,
91 "Coda VFS statistics\n"
92 "===================\n\n"
93 "File Operations:\n"
94 "\topen\t\t%9d\n"
95 "\tflush\t\t%9d\n"
96 "\trelease\t\t%9d\n"
97 "\tfsync\t\t%9d\n\n"
98 "Dir Operations:\n"
99 "\treaddir\t\t%9d\n\n"
100 "Inode Operations\n"
101 "\tcreate\t\t%9d\n"
102 "\tlookup\t\t%9d\n"
103 "\tlink\t\t%9d\n"
104 "\tunlink\t\t%9d\n"
105 "\tsymlink\t\t%9d\n"
106 "\tmkdir\t\t%9d\n"
107 "\trmdir\t\t%9d\n"
108 "\trename\t\t%9d\n"
109 "\tpermission\t%9d\n",
110
111 /* file operations */
112 ps->open,
113 ps->flush,
114 ps->release,
115 ps->fsync,
116
117 /* dir operations */
118 ps->readdir,
119
120 /* inode operations */
121 ps->create,
122 ps->lookup,
123 ps->link,
124 ps->unlink,
125 ps->symlink,
126 ps->mkdir,
127 ps->rmdir,
128 ps->rename,
129 ps->permission);
130 return 0;
131}
132
133static int proc_cache_inv_stats_show(struct seq_file *m, void *v)
134{
135 struct coda_cache_inv_stats * ps = & coda_cache_inv_stat;
136
137 seq_printf(m,
138 "Coda cache invalidation statistics\n"
139 "==================================\n\n"
140 "flush\t\t%9d\n"
141 "purge user\t%9d\n"
142 "zap_dir\t\t%9d\n"
143 "zap_file\t%9d\n"
144 "zap_vnode\t%9d\n"
145 "purge_fid\t%9d\n"
146 "replace\t\t%9d\n",
147 ps->flush,
148 ps->purge_user,
149 ps->zap_dir,
150 ps->zap_file,
151 ps->zap_vnode,
152 ps->purge_fid,
153 ps->replace );
154 return 0;
155}
156
157static int proc_vfs_stats_open(struct inode *inode, struct file *file)
158{
159 return single_open(file, proc_vfs_stats_show, NULL);
160}
161
162static int proc_cache_inv_stats_open(struct inode *inode, struct file *file)
163{
164 return single_open(file, proc_cache_inv_stats_show, NULL);
165}
166
167static const struct file_operations proc_vfs_stats_fops = {
168 .owner = THIS_MODULE,
169 .open = proc_vfs_stats_open,
170 .read = seq_read,
171 .llseek = seq_lseek,
172 .release = single_release,
173};
174
175static const struct file_operations proc_cache_inv_stats_fops = {
176 .owner = THIS_MODULE,
177 .open = proc_cache_inv_stats_open,
178 .read = seq_read,
179 .llseek = seq_lseek,
180 .release = single_release,
181};
182
183static ctl_table coda_table[] = { 16static ctl_table coda_table[] = {
184 { 17 {
185 .ctl_name = CTL_UNNUMBERED, 18 .ctl_name = CTL_UNNUMBERED,
@@ -199,22 +32,6 @@ static ctl_table coda_table[] = {
199 }, 32 },
200 { 33 {
201 .ctl_name = CTL_UNNUMBERED, 34 .ctl_name = CTL_UNNUMBERED,
202 .procname = "vfs_stats",
203 .data = NULL,
204 .maxlen = 0,
205 .mode = 0644,
206 .proc_handler = &do_reset_coda_vfs_stats
207 },
208 {
209 .ctl_name = CTL_UNNUMBERED,
210 .procname = "cache_inv_stats",
211 .data = NULL,
212 .maxlen = 0,
213 .mode = 0644,
214 .proc_handler = &do_reset_coda_cache_inv_stats
215 },
216 {
217 .ctl_name = CTL_UNNUMBERED,
218 .procname = "fake_statfs", 35 .procname = "fake_statfs",
219 .data = &coda_fake_statfs, 36 .data = &coda_fake_statfs,
220 .maxlen = sizeof(int), 37 .maxlen = sizeof(int),
@@ -235,59 +52,20 @@ static ctl_table fs_table[] = {
235}; 52};
236 53
237 54
238#ifdef CONFIG_PROC_FS
239
240/*
241 target directory structure:
242 /proc/fs (see linux/fs/proc/root.c)
243 /proc/fs/coda
244 /proc/fs/coda/{vfs_stats,
245
246*/
247
248static struct proc_dir_entry* proc_fs_coda;
249
250#endif
251
252void coda_sysctl_init(void) 55void coda_sysctl_init(void)
253{ 56{
254 reset_coda_vfs_stats();
255 reset_coda_cache_inv_stats();
256
257#ifdef CONFIG_PROC_FS
258 proc_fs_coda = proc_mkdir("coda", proc_root_fs);
259 if (proc_fs_coda) {
260 struct proc_dir_entry *pde;
261
262 proc_fs_coda->owner = THIS_MODULE;
263 pde = create_proc_entry("vfs_stats", 0, proc_fs_coda);
264 if (pde)
265 pde->proc_fops = &proc_vfs_stats_fops;
266 pde = create_proc_entry("cache_inv_stats", 0, proc_fs_coda);
267 if (pde)
268 pde->proc_fops = &proc_cache_inv_stats_fops;
269 }
270#endif
271
272#ifdef CONFIG_SYSCTL 57#ifdef CONFIG_SYSCTL
273 if ( !fs_table_header ) 58 if ( !fs_table_header )
274 fs_table_header = register_sysctl_table(fs_table); 59 fs_table_header = register_sysctl_table(fs_table);
275#endif 60#endif
276} 61}
277 62
278void coda_sysctl_clean(void) 63void coda_sysctl_clean(void)
279{ 64{
280
281#ifdef CONFIG_SYSCTL 65#ifdef CONFIG_SYSCTL
282 if ( fs_table_header ) { 66 if ( fs_table_header ) {
283 unregister_sysctl_table(fs_table_header); 67 unregister_sysctl_table(fs_table_header);
284 fs_table_header = NULL; 68 fs_table_header = NULL;
285 } 69 }
286#endif 70#endif
287
288#ifdef CONFIG_PROC_FS
289 remove_proc_entry("cache_inv_stats", proc_fs_coda);
290 remove_proc_entry("vfs_stats", proc_fs_coda);
291 remove_proc_entry("coda", proc_root_fs);
292#endif
293} 71}
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 5faacdb1a479..e4e766e5557c 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -35,12 +35,10 @@
35#include <linux/coda_psdev.h> 35#include <linux/coda_psdev.h>
36#include <linux/coda_fs_i.h> 36#include <linux/coda_fs_i.h>
37#include <linux/coda_cache.h> 37#include <linux/coda_cache.h>
38#include <linux/coda_proc.h>
39 38
40#define upc_alloc() kmalloc(sizeof(struct upc_req), GFP_KERNEL) 39#include "coda_int.h"
41#define upc_free(r) kfree(r)
42 40
43static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize, 41static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
44 union inputArgs *buffer); 42 union inputArgs *buffer);
45 43
46static void *alloc_upcall(int opcode, int size) 44static void *alloc_upcall(int opcode, int size)
@@ -86,13 +84,9 @@ int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
86 insize = SIZE(root); 84 insize = SIZE(root);
87 UPARG(CODA_ROOT); 85 UPARG(CODA_ROOT);
88 86
89 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 87 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
90 88 if (!error)
91 if (error) {
92 printk("coda_get_rootfid: error %d\n", error);
93 } else {
94 *fidp = outp->coda_root.VFid; 89 *fidp = outp->coda_root.VFid;
95 }
96 90
97 CODA_FREE(inp, insize); 91 CODA_FREE(inp, insize);
98 return error; 92 return error;
@@ -109,9 +103,9 @@ int venus_getattr(struct super_block *sb, struct CodaFid *fid,
109 UPARG(CODA_GETATTR); 103 UPARG(CODA_GETATTR);
110 inp->coda_getattr.VFid = *fid; 104 inp->coda_getattr.VFid = *fid;
111 105
112 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 106 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
113 107 if (!error)
114 *attr = outp->coda_getattr.attr; 108 *attr = outp->coda_getattr.attr;
115 109
116 CODA_FREE(inp, insize); 110 CODA_FREE(inp, insize);
117 return error; 111 return error;
@@ -130,7 +124,7 @@ int venus_setattr(struct super_block *sb, struct CodaFid *fid,
130 inp->coda_setattr.VFid = *fid; 124 inp->coda_setattr.VFid = *fid;
131 inp->coda_setattr.attr = *vattr; 125 inp->coda_setattr.attr = *vattr;
132 126
133 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 127 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
134 128
135 CODA_FREE(inp, insize); 129 CODA_FREE(inp, insize);
136 return error; 130 return error;
@@ -156,10 +150,11 @@ int venus_lookup(struct super_block *sb, struct CodaFid *fid,
156 memcpy((char *)(inp) + offset, name, length); 150 memcpy((char *)(inp) + offset, name, length);
157 *((char *)inp + offset + length) = '\0'; 151 *((char *)inp + offset + length) = '\0';
158 152
159 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 153 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
160 154 if (!error) {
161 *resfid = outp->coda_lookup.VFid; 155 *resfid = outp->coda_lookup.VFid;
162 *type = outp->coda_lookup.vtype; 156 *type = outp->coda_lookup.vtype;
157 }
163 158
164 CODA_FREE(inp, insize); 159 CODA_FREE(inp, insize);
165 return error; 160 return error;
@@ -188,7 +183,7 @@ int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
188 inp->coda_store.VFid = *fid; 183 inp->coda_store.VFid = *fid;
189 inp->coda_store.flags = flags; 184 inp->coda_store.flags = flags;
190 185
191 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 186 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
192 187
193 CODA_FREE(inp, insize); 188 CODA_FREE(inp, insize);
194 return error; 189 return error;
@@ -206,7 +201,7 @@ int venus_release(struct super_block *sb, struct CodaFid *fid, int flags)
206 inp->coda_release.VFid = *fid; 201 inp->coda_release.VFid = *fid;
207 inp->coda_release.flags = flags; 202 inp->coda_release.flags = flags;
208 203
209 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 204 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
210 205
211 CODA_FREE(inp, insize); 206 CODA_FREE(inp, insize);
212 return error; 207 return error;
@@ -235,7 +230,7 @@ int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
235 inp->coda_close.VFid = *fid; 230 inp->coda_close.VFid = *fid;
236 inp->coda_close.flags = flags; 231 inp->coda_close.flags = flags;
237 232
238 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 233 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
239 234
240 CODA_FREE(inp, insize); 235 CODA_FREE(inp, insize);
241 return error; 236 return error;
@@ -251,12 +246,12 @@ int venus_open(struct super_block *sb, struct CodaFid *fid,
251 insize = SIZE(open_by_fd); 246 insize = SIZE(open_by_fd);
252 UPARG(CODA_OPEN_BY_FD); 247 UPARG(CODA_OPEN_BY_FD);
253 248
254 inp->coda_open.VFid = *fid; 249 inp->coda_open_by_fd.VFid = *fid;
255 inp->coda_open.flags = flags; 250 inp->coda_open_by_fd.flags = flags;
256 251
257 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 252 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
258 253 if (!error)
259 *fh = outp->coda_open_by_fd.fh; 254 *fh = outp->coda_open_by_fd.fh;
260 255
261 CODA_FREE(inp, insize); 256 CODA_FREE(inp, insize);
262 return error; 257 return error;
@@ -281,11 +276,12 @@ int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
281 /* Venus must get null terminated string */ 276 /* Venus must get null terminated string */
282 memcpy((char *)(inp) + offset, name, length); 277 memcpy((char *)(inp) + offset, name, length);
283 *((char *)inp + offset + length) = '\0'; 278 *((char *)inp + offset + length) = '\0';
284
285 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
286 279
287 *attrs = outp->coda_mkdir.attr; 280 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
288 *newfid = outp->coda_mkdir.VFid; 281 if (!error) {
282 *attrs = outp->coda_mkdir.attr;
283 *newfid = outp->coda_mkdir.VFid;
284 }
289 285
290 CODA_FREE(inp, insize); 286 CODA_FREE(inp, insize);
291 return error; 287 return error;
@@ -323,7 +319,7 @@ int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
323 memcpy((char *)(inp) + offset, new_name, new_length); 319 memcpy((char *)(inp) + offset, new_name, new_length);
324 *((char *)inp + offset + new_length) = '\0'; 320 *((char *)inp + offset + new_length) = '\0';
325 321
326 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 322 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
327 323
328 CODA_FREE(inp, insize); 324 CODA_FREE(inp, insize);
329 return error; 325 return error;
@@ -351,11 +347,12 @@ int venus_create(struct super_block *sb, struct CodaFid *dirfid,
351 /* Venus must get null terminated string */ 347 /* Venus must get null terminated string */
352 memcpy((char *)(inp) + offset, name, length); 348 memcpy((char *)(inp) + offset, name, length);
353 *((char *)inp + offset + length) = '\0'; 349 *((char *)inp + offset + length) = '\0';
354
355 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
356 350
357 *attrs = outp->coda_create.attr; 351 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
358 *newfid = outp->coda_create.VFid; 352 if (!error) {
353 *attrs = outp->coda_create.attr;
354 *newfid = outp->coda_create.VFid;
355 }
359 356
360 CODA_FREE(inp, insize); 357 CODA_FREE(inp, insize);
361 return error; 358 return error;
@@ -377,8 +374,8 @@ int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
377 inp->coda_rmdir.name = offset; 374 inp->coda_rmdir.name = offset;
378 memcpy((char *)(inp) + offset, name, length); 375 memcpy((char *)(inp) + offset, name, length);
379 *((char *)inp + offset + length) = '\0'; 376 *((char *)inp + offset + length) = '\0';
380 377
381 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 378 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
382 379
383 CODA_FREE(inp, insize); 380 CODA_FREE(inp, insize);
384 return error; 381 return error;
@@ -399,8 +396,8 @@ int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
399 inp->coda_remove.name = offset; 396 inp->coda_remove.name = offset;
400 memcpy((char *)(inp) + offset, name, length); 397 memcpy((char *)(inp) + offset, name, length);
401 *((char *)inp + offset + length) = '\0'; 398 *((char *)inp + offset + length) = '\0';
402 399
403 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 400 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
404 401
405 CODA_FREE(inp, insize); 402 CODA_FREE(inp, insize);
406 return error; 403 return error;
@@ -420,19 +417,18 @@ int venus_readlink(struct super_block *sb, struct CodaFid *fid,
420 UPARG(CODA_READLINK); 417 UPARG(CODA_READLINK);
421 418
422 inp->coda_readlink.VFid = *fid; 419 inp->coda_readlink.VFid = *fid;
423 420
424 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 421 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
425 422 if (!error) {
426 if (! error) { 423 retlen = outp->coda_readlink.count;
427 retlen = outp->coda_readlink.count;
428 if ( retlen > *length ) 424 if ( retlen > *length )
429 retlen = *length; 425 retlen = *length;
430 *length = retlen; 426 *length = retlen;
431 result = (char *)outp + (long)outp->coda_readlink.data; 427 result = (char *)outp + (long)outp->coda_readlink.data;
432 memcpy(buffer, result, retlen); 428 memcpy(buffer, result, retlen);
433 *(buffer + retlen) = '\0'; 429 *(buffer + retlen) = '\0';
434 } 430 }
435 431
436 CODA_FREE(inp, insize); 432 CODA_FREE(inp, insize);
437 return error; 433 return error;
438} 434}
@@ -458,8 +454,8 @@ int venus_link(struct super_block *sb, struct CodaFid *fid,
458 /* make sure strings are null terminated */ 454 /* make sure strings are null terminated */
459 memcpy((char *)(inp) + offset, name, len); 455 memcpy((char *)(inp) + offset, name, len);
460 *((char *)inp + offset + len) = '\0'; 456 *((char *)inp + offset + len) = '\0';
461 457
462 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 458 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
463 459
464 CODA_FREE(inp, insize); 460 CODA_FREE(inp, insize);
465 return error; 461 return error;
@@ -494,7 +490,7 @@ int venus_symlink(struct super_block *sb, struct CodaFid *fid,
494 memcpy((char *)(inp) + offset, name, len); 490 memcpy((char *)(inp) + offset, name, len);
495 *((char *)inp + offset + len) = '\0'; 491 *((char *)inp + offset + len) = '\0';
496 492
497 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 493 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
498 494
499 CODA_FREE(inp, insize); 495 CODA_FREE(inp, insize);
500 return error; 496 return error;
@@ -509,9 +505,9 @@ int venus_fsync(struct super_block *sb, struct CodaFid *fid)
509 insize=SIZE(fsync); 505 insize=SIZE(fsync);
510 UPARG(CODA_FSYNC); 506 UPARG(CODA_FSYNC);
511 507
512 inp->coda_fsync.VFid = *fid; 508 inp->coda_fsync.VFid = *fid;
513 error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs), 509 error = coda_upcall(coda_vcp(sb), sizeof(union inputArgs),
514 &outsize, inp); 510 &outsize, inp);
515 511
516 CODA_FREE(inp, insize); 512 CODA_FREE(inp, insize);
517 return error; 513 return error;
@@ -529,7 +525,7 @@ int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
529 inp->coda_access.VFid = *fid; 525 inp->coda_access.VFid = *fid;
530 inp->coda_access.flags = mask; 526 inp->coda_access.flags = mask;
531 527
532 error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); 528 error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
533 529
534 CODA_FREE(inp, insize); 530 CODA_FREE(inp, insize);
535 return error; 531 return error;
@@ -578,9 +574,9 @@ int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
578 goto exit; 574 goto exit;
579 } 575 }
580 576
581 error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size, 577 error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
582 &outsize, inp); 578 &outsize, inp);
583 579
584 if (error) { 580 if (error) {
585 printk("coda_pioctl: Venus returns: %d for %s\n", 581 printk("coda_pioctl: Venus returns: %d for %s\n",
586 error, coda_f2s(fid)); 582 error, coda_f2s(fid));
@@ -620,16 +616,13 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
620 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs)); 616 insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
621 UPARG(CODA_STATFS); 617 UPARG(CODA_STATFS);
622 618
623 error = coda_upcall(coda_sbp(dentry->d_sb), insize, &outsize, inp); 619 error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
624 620 if (!error) {
625 if (!error) {
626 sfs->f_blocks = outp->coda_statfs.stat.f_blocks; 621 sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
627 sfs->f_bfree = outp->coda_statfs.stat.f_bfree; 622 sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
628 sfs->f_bavail = outp->coda_statfs.stat.f_bavail; 623 sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
629 sfs->f_files = outp->coda_statfs.stat.f_files; 624 sfs->f_files = outp->coda_statfs.stat.f_files;
630 sfs->f_ffree = outp->coda_statfs.stat.f_ffree; 625 sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
631 } else {
632 printk("coda_statfs: Venus returns: %d\n", error);
633 } 626 }
634 627
635 CODA_FREE(inp, insize); 628 CODA_FREE(inp, insize);
@@ -638,96 +631,129 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
638 631
639/* 632/*
640 * coda_upcall and coda_downcall routines. 633 * coda_upcall and coda_downcall routines.
641 *
642 */ 634 */
635static void block_signals(sigset_t *old)
636{
637 spin_lock_irq(&current->sighand->siglock);
638 *old = current->blocked;
639
640 sigfillset(&current->blocked);
641 sigdelset(&current->blocked, SIGKILL);
642 sigdelset(&current->blocked, SIGSTOP);
643 sigdelset(&current->blocked, SIGINT);
644
645 recalc_sigpending();
646 spin_unlock_irq(&current->sighand->siglock);
647}
648
649static void unblock_signals(sigset_t *old)
650{
651 spin_lock_irq(&current->sighand->siglock);
652 current->blocked = *old;
653 recalc_sigpending();
654 spin_unlock_irq(&current->sighand->siglock);
655}
656
657/* Don't allow signals to interrupt the following upcalls before venus
658 * has seen them,
659 * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems)
660 * - CODA_STORE (to avoid data loss)
661 */
662#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
663 (((r)->uc_opcode != CODA_CLOSE && \
664 (r)->uc_opcode != CODA_STORE && \
665 (r)->uc_opcode != CODA_RELEASE) || \
666 (r)->uc_flags & REQ_READ))
643 667
644static inline void coda_waitfor_upcall(struct upc_req *vmp, 668static inline void coda_waitfor_upcall(struct upc_req *req)
645 struct venus_comm *vcommp)
646{ 669{
647 DECLARE_WAITQUEUE(wait, current); 670 DECLARE_WAITQUEUE(wait, current);
671 unsigned long timeout = jiffies + coda_timeout * HZ;
672 sigset_t old;
673 int blocked;
648 674
649 vmp->uc_posttime = jiffies; 675 block_signals(&old);
676 blocked = 1;
650 677
651 add_wait_queue(&vmp->uc_sleep, &wait); 678 add_wait_queue(&req->uc_sleep, &wait);
652 for (;;) { 679 for (;;) {
653 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE ) 680 if (CODA_INTERRUPTIBLE(req))
654 set_current_state(TASK_INTERRUPTIBLE); 681 set_current_state(TASK_INTERRUPTIBLE);
655 else 682 else
656 set_current_state(TASK_UNINTERRUPTIBLE); 683 set_current_state(TASK_UNINTERRUPTIBLE);
657 684
658 /* venus died */
659 if ( !vcommp->vc_inuse )
660 break;
661
662 /* got a reply */ 685 /* got a reply */
663 if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) ) 686 if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
664 break; 687 break;
665 688
666 if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) { 689 if (blocked && time_after(jiffies, timeout) &&
667 /* if this process really wants to die, let it go */ 690 CODA_INTERRUPTIBLE(req))
668 if ( sigismember(&(current->pending.signal), SIGKILL) || 691 {
669 sigismember(&(current->pending.signal), SIGINT) ) 692 unblock_signals(&old);
670 break; 693 blocked = 0;
671 /* signal is present: after timeout always return 694 }
672 really smart idea, probably useless ... */ 695
673 if ( jiffies - vmp->uc_posttime > coda_timeout * HZ ) 696 if (signal_pending(current)) {
674 break; 697 list_del(&req->uc_chain);
698 break;
675 } 699 }
676 schedule(); 700
701 if (blocked)
702 schedule_timeout(HZ);
703 else
704 schedule();
677 } 705 }
678 remove_wait_queue(&vmp->uc_sleep, &wait); 706 if (blocked)
679 set_current_state(TASK_RUNNING); 707 unblock_signals(&old);
680 708
681 return; 709 remove_wait_queue(&req->uc_sleep, &wait);
710 set_current_state(TASK_RUNNING);
682} 711}
683 712
684 713
685/* 714/*
686 * coda_upcall will return an error in the case of 715 * coda_upcall will return an error in the case of
687 * failed communication with Venus _or_ will peek at Venus 716 * failed communication with Venus _or_ will peek at Venus
688 * reply and return Venus' error. 717 * reply and return Venus' error.
689 * 718 *
690 * As venus has 2 types of errors, normal errors (positive) and internal 719 * As venus has 2 types of errors, normal errors (positive) and internal
691 * errors (negative), normal errors are negated, while internal errors 720 * errors (negative), normal errors are negated, while internal errors
692 * are all mapped to -EINTR, while showing a nice warning message. (jh) 721 * are all mapped to -EINTR, while showing a nice warning message. (jh)
693 *
694 */ 722 */
695static int coda_upcall(struct coda_sb_info *sbi, 723static int coda_upcall(struct venus_comm *vcp,
696 int inSize, int *outSize, 724 int inSize, int *outSize,
697 union inputArgs *buffer) 725 union inputArgs *buffer)
698{ 726{
699 struct venus_comm *vcommp;
700 union outputArgs *out; 727 union outputArgs *out;
701 struct upc_req *req; 728 union inputArgs *sig_inputArgs;
729 struct upc_req *req, *sig_req;
702 int error = 0; 730 int error = 0;
703 731
704 vcommp = sbi->sbi_vcomm; 732 if (!vcp->vc_inuse) {
705 if ( !vcommp->vc_inuse ) { 733 printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
706 printk("No pseudo device in upcall comms at %p\n", vcommp); 734 return -ENXIO;
707 return -ENXIO;
708 } 735 }
709 736
710 /* Format the request message. */ 737 /* Format the request message. */
711 req = upc_alloc(); 738 req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
712 if (!req) { 739 if (!req)
713 printk("Failed to allocate upc_req structure\n");
714 return -ENOMEM; 740 return -ENOMEM;
715 } 741
716 req->uc_data = (void *)buffer; 742 req->uc_data = (void *)buffer;
717 req->uc_flags = 0; 743 req->uc_flags = 0;
718 req->uc_inSize = inSize; 744 req->uc_inSize = inSize;
719 req->uc_outSize = *outSize ? *outSize : inSize; 745 req->uc_outSize = *outSize ? *outSize : inSize;
720 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode; 746 req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
721 req->uc_unique = ++vcommp->vc_seq; 747 req->uc_unique = ++vcp->vc_seq;
722 init_waitqueue_head(&req->uc_sleep); 748 init_waitqueue_head(&req->uc_sleep);
723 749
724 /* Fill in the common input args. */ 750 /* Fill in the common input args. */
725 ((union inputArgs *)buffer)->ih.unique = req->uc_unique; 751 ((union inputArgs *)buffer)->ih.unique = req->uc_unique;
726 752
727 /* Append msg to pending queue and poke Venus. */ 753 /* Append msg to pending queue and poke Venus. */
728 list_add_tail(&(req->uc_chain), &vcommp->vc_pending); 754 list_add_tail(&req->uc_chain, &vcp->vc_pending);
729 755
730 wake_up_interruptible(&vcommp->vc_waitq); 756 wake_up_interruptible(&vcp->vc_waitq);
731 /* We can be interrupted while we wait for Venus to process 757 /* We can be interrupted while we wait for Venus to process
732 * our request. If the interrupt occurs before Venus has read 758 * our request. If the interrupt occurs before Venus has read
733 * the request, we dequeue and return. If it occurs after the 759 * the request, we dequeue and return. If it occurs after the
@@ -738,67 +764,60 @@ static int coda_upcall(struct coda_sb_info *sbi,
738 * ENODEV. */ 764 * ENODEV. */
739 765
740 /* Go to sleep. Wake up on signals only after the timeout. */ 766 /* Go to sleep. Wake up on signals only after the timeout. */
741 coda_waitfor_upcall(req, vcommp); 767 coda_waitfor_upcall(req);
742 768
743 if (vcommp->vc_inuse) { /* i.e. Venus is still alive */ 769 /* Op went through, interrupt or not... */
744 /* Op went through, interrupt or not... */ 770 if (req->uc_flags & REQ_WRITE) {
745 if (req->uc_flags & REQ_WRITE) {
746 out = (union outputArgs *)req->uc_data; 771 out = (union outputArgs *)req->uc_data;
747 /* here we map positive Venus errors to kernel errors */ 772 /* here we map positive Venus errors to kernel errors */
748 error = -out->oh.result; 773 error = -out->oh.result;
749 *outSize = req->uc_outSize; 774 *outSize = req->uc_outSize;
750 goto exit; 775 goto exit;
751 } 776 }
752 if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) { 777
753 /* Interrupted before venus read it. */ 778 error = -EINTR;
754 list_del(&(req->uc_chain)); 779 if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) {
755 /* perhaps the best way to convince the app to 780 printk(KERN_WARNING "coda: Unexpected interruption.\n");
756 give up? */
757 error = -EINTR;
758 goto exit; 781 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 } 782 }
799 783
800 exit: 784 /* Interrupted before venus read it. */
801 upc_free(req); 785 if (!(req->uc_flags & REQ_READ))
786 goto exit;
787
788 /* Venus saw the upcall, make sure we can send interrupt signal */
789 if (!vcp->vc_inuse) {
790 printk(KERN_INFO "coda: Venus dead, not sending signal.\n");
791 goto exit;
792 }
793
794 error = -ENOMEM;
795 sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
796 if (!sig_req) goto exit;
797
798 CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
799 if (!sig_req->uc_data) {
800 kfree(sig_req);
801 goto exit;
802 }
803
804 error = -EINTR;
805 sig_inputArgs = (union inputArgs *)sig_req->uc_data;
806 sig_inputArgs->ih.opcode = CODA_SIGNAL;
807 sig_inputArgs->ih.unique = req->uc_unique;
808
809 sig_req->uc_flags = REQ_ASYNC;
810 sig_req->uc_opcode = sig_inputArgs->ih.opcode;
811 sig_req->uc_unique = sig_inputArgs->ih.unique;
812 sig_req->uc_inSize = sizeof(struct coda_in_hdr);
813 sig_req->uc_outSize = sizeof(struct coda_in_hdr);
814
815 /* insert at head of queue! */
816 list_add(&(sig_req->uc_chain), &vcp->vc_pending);
817 wake_up_interruptible(&vcp->vc_waitq);
818
819exit:
820 kfree(req);
802 return error; 821 return error;
803} 822}
804 823
@@ -838,77 +857,66 @@ static int coda_upcall(struct coda_sb_info *sbi,
838 857
839int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb) 858int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
840{ 859{
860 struct inode *inode = NULL;
861 struct CodaFid *fid, *newfid;
862
841 /* Handle invalidation requests. */ 863 /* Handle invalidation requests. */
842 if ( !sb || !sb->s_root || !sb->s_root->d_inode) 864 if ( !sb || !sb->s_root)
843 return 0; 865 return 0;
844 866
845 switch (opcode) { 867 switch (opcode) {
846 868 case CODA_FLUSH:
847 case CODA_FLUSH : { 869 coda_cache_clear_all(sb);
848 coda_cache_clear_all(sb); 870 shrink_dcache_sb(sb);
849 shrink_dcache_sb(sb); 871 if (sb->s_root->d_inode)
850 coda_flag_inode(sb->s_root->d_inode, C_FLUSH); 872 coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
851 return(0); 873 break;
852 } 874
853 875 case CODA_PURGEUSER:
854 case CODA_PURGEUSER : { 876 coda_cache_clear_all(sb);
855 coda_cache_clear_all(sb); 877 break;
856 return(0); 878
857 } 879 case CODA_ZAPDIR:
858 880 fid = &out->coda_zapdir.CodaFid;
859 case CODA_ZAPDIR : { 881 inode = coda_fid_to_inode(fid, sb);
860 struct inode *inode; 882 if (inode) {
861 struct CodaFid *fid = &out->coda_zapdir.CodaFid; 883 coda_flag_inode_children(inode, C_PURGE);
862 884 coda_flag_inode(inode, C_VATTR);
863 inode = coda_fid_to_inode(fid, sb); 885 }
864 if (inode) { 886 break;
865 coda_flag_inode_children(inode, C_PURGE); 887
866 coda_flag_inode(inode, C_VATTR); 888 case CODA_ZAPFILE:
867 iput(inode); 889 fid = &out->coda_zapfile.CodaFid;
868 } 890 inode = coda_fid_to_inode(fid, sb);
869 891 if (inode)
870 return(0); 892 coda_flag_inode(inode, C_VATTR);
871 } 893 break;
872 894
873 case CODA_ZAPFILE : { 895 case CODA_PURGEFID:
874 struct inode *inode; 896 fid = &out->coda_purgefid.CodaFid;
875 struct CodaFid *fid = &out->coda_zapfile.CodaFid; 897 inode = coda_fid_to_inode(fid, sb);
876 inode = coda_fid_to_inode(fid, sb); 898 if (inode) {
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); 899 coda_flag_inode_children(inode, C_PURGE);
890 900
891 /* catch the dentries later if some are still busy */ 901 /* catch the dentries later if some are still busy */
892 coda_flag_inode(inode, C_PURGE); 902 coda_flag_inode(inode, C_PURGE);
893 d_prune_aliases(inode); 903 d_prune_aliases(inode);
894 904
895 iput(inode); 905 }
896 } 906 break;
897 return 0; 907
898 } 908 case CODA_REPLACE:
899 909 fid = &out->coda_replace.OldFid;
900 case CODA_REPLACE : { 910 newfid = &out->coda_replace.NewFid;
901 struct inode *inode; 911 inode = coda_fid_to_inode(fid, sb);
902 struct CodaFid *oldfid = &out->coda_replace.OldFid; 912 if (inode)
903 struct CodaFid *newfid = &out->coda_replace.NewFid; 913 coda_replace_fid(inode, fid, newfid);
904 inode = coda_fid_to_inode(oldfid, sb); 914 break;
905 if ( inode ) { 915 }
906 coda_replace_fid(inode, oldfid, newfid); 916
907 iput(inode); 917 if (inode)
908 } 918 iput(inode);
909 return 0; 919
910 } 920 return 0;
911 }
912 return 0;
913} 921}
914 922