diff options
Diffstat (limited to 'fs/coda')
-rw-r--r-- | fs/coda/cache.c | 7 | ||||
-rw-r--r-- | fs/coda/cnode.c | 7 | ||||
-rw-r--r-- | fs/coda/coda_int.h | 7 | ||||
-rw-r--r-- | fs/coda/dir.c | 286 | ||||
-rw-r--r-- | fs/coda/file.c | 17 | ||||
-rw-r--r-- | fs/coda/inode.c | 46 | ||||
-rw-r--r-- | fs/coda/psdev.c | 88 | ||||
-rw-r--r-- | fs/coda/symlink.c | 2 | ||||
-rw-r--r-- | fs/coda/sysctl.c | 228 | ||||
-rw-r--r-- | fs/coda/upcall.c | 454 |
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) | |||
43 | void coda_cache_clear_inode(struct inode *inode) | 43 | void 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 */ |
50 | void coda_cache_clear_all(struct super_block *sb) | 50 | void 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 | ||
58 | static int coda_fail_inode(struct inode *inode, void *data) | ||
59 | { | ||
60 | return -1; | ||
61 | } | ||
62 | |||
63 | struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid, | 58 | struct 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 | ||
4 | struct dentry; | ||
5 | |||
4 | extern struct file_system_type coda_fs_type; | 6 | extern struct file_system_type coda_fs_type; |
7 | extern unsigned long coda_timeout; | ||
8 | extern int coda_hard; | ||
9 | extern int coda_fake_statfs; | ||
5 | 10 | ||
6 | void coda_destroy_inodecache(void); | 11 | void coda_destroy_inodecache(void); |
7 | int coda_init_inodecache(void); | 12 | int coda_init_inodecache(void); |
8 | int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, | 13 | int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, |
9 | int datasync); | 14 | int datasync); |
15 | void coda_sysctl_init(void); | ||
16 | void 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 */ |
46 | static int coda_readdir(struct file *file, void *dirent, filldir_t filldir); | 45 | static int coda_readdir(struct file *file, void *buf, filldir_t filldir); |
47 | 46 | ||
48 | /* dentry ops */ | 47 | /* dentry ops */ |
49 | static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd); | 48 | static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd); |
50 | static int coda_dentry_delete(struct dentry *); | 49 | static int coda_dentry_delete(struct dentry *); |
51 | 50 | ||
52 | /* support routines */ | 51 | /* support routines */ |
53 | static int coda_venus_readdir(struct file *filp, filldir_t filldir, | 52 | static 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 */ |
57 | static int coda_return_EIO(void) | 56 | static 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 */ |
98 | static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd) | 97 | static 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 | ||
142 | exit: | 131 | exit: |
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 | ||
181 | static inline void coda_dir_changed(struct inode *dir, int link) | 164 | static 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 */ | ||
183 | static inline void coda_dir_inc_nlink(struct inode *dir) | ||
184 | { | ||
185 | if (dir->i_nlink >= 2) | ||
186 | inc_nlink(dir); | ||
187 | } | ||
188 | |||
189 | static 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 | ||
238 | static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) | 235 | static 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 | ||
309 | out: | 305 | out: |
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 | ||
376 | int coda_rmdir(struct inode *dir, struct dentry *de) | 369 | int 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 */ |
405 | static int coda_rename(struct inode *old_dir, struct dentry *old_dentry, | 392 | static 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 */ |
442 | int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir) | 428 | int 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 | } |
477 | out: | 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 */ |
504 | static int coda_venus_readdir(struct file *filp, filldir_t filldir, | 487 | static 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 | ||
84 | static int coda_remount(struct super_block *sb, int *flags, char *data) | 84 | static 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 | ||
142 | static int coda_fill_super(struct super_block *sb, void *data, int silent) | 142 | static 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 | ||
221 | static void coda_put_super(struct super_block *sb) | 210 | static 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 | ||
232 | static void coda_clear_inode(struct inode *inode) | 218 | static 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 */ |
55 | int coda_hard; /* allows signals during upcalls */ | 52 | int coda_hard; /* allows signals during upcalls */ |
56 | unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */ | 53 | unsigned 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); |
267 | out: | 265 | out: |
268 | unlock_kernel(); | 266 | unlock_kernel(); |
269 | return (count ? count : retval); | 267 | return (count ? count : retval); |
@@ -271,71 +269,70 @@ out: | |||
271 | 269 | ||
272 | static int coda_psdev_open(struct inode * inode, struct file * file) | 270 | static 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 | ||
305 | static int coda_psdev_release(struct inode * inode, struct file * file) | 301 | static 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 | 376 | MODULE_AUTHOR("Jan Harkes, Peter J. Braam"); | |
380 | MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>"); | 377 | MODULE_DESCRIPTION("Coda Distributed File System VFS interface"); |
378 | MODULE_ALIAS_CHARDEV_MAJOR(CODA_PSDEV_MAJOR); | ||
381 | MODULE_LICENSE("GPL"); | 379 | MODULE_LICENSE("GPL"); |
380 | #ifdef CONFIG_CODA_FS_OLD_API | ||
381 | MODULE_VERSION("5.3.21"); | ||
382 | #else | ||
383 | MODULE_VERSION("6.6"); | ||
384 | #endif | ||
382 | 385 | ||
383 | static int __init init_coda(void) | 386 | static 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 | ||
25 | static int coda_symlink_filler(struct file *file, struct page *page) | 24 | static 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 | ||
34 | static struct ctl_table_header *fs_table_header; | 14 | static 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 | |||
42 | struct coda_vfs_stats coda_vfs_stat; | ||
43 | static struct coda_cache_inv_stats coda_cache_inv_stat; | ||
44 | |||
45 | static void reset_coda_vfs_stats( void ) | ||
46 | { | ||
47 | memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) ); | ||
48 | } | ||
49 | |||
50 | static void reset_coda_cache_inv_stats( void ) | ||
51 | { | ||
52 | memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) ); | ||
53 | } | ||
54 | |||
55 | static 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 | |||
70 | static 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 | |||
86 | static 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 | |||
133 | static 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 | |||
157 | static int proc_vfs_stats_open(struct inode *inode, struct file *file) | ||
158 | { | ||
159 | return single_open(file, proc_vfs_stats_show, NULL); | ||
160 | } | ||
161 | |||
162 | static 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 | |||
167 | static 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 | |||
175 | static 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 | |||
183 | static ctl_table coda_table[] = { | 16 | static 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 | |||
248 | static struct proc_dir_entry* proc_fs_coda; | ||
249 | |||
250 | #endif | ||
251 | |||
252 | void coda_sysctl_init(void) | 55 | void 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 | ||
278 | void coda_sysctl_clean(void) | 63 | void 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 | ||
43 | static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize, | 41 | static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize, |
44 | union inputArgs *buffer); | 42 | union inputArgs *buffer); |
45 | 43 | ||
46 | static void *alloc_upcall(int opcode, int size) | 44 | static 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 | */ |
635 | static void block_signals(sigset_t *old) | ||
636 | { | ||
637 | spin_lock_irq(¤t->sighand->siglock); | ||
638 | *old = current->blocked; | ||
639 | |||
640 | sigfillset(¤t->blocked); | ||
641 | sigdelset(¤t->blocked, SIGKILL); | ||
642 | sigdelset(¤t->blocked, SIGSTOP); | ||
643 | sigdelset(¤t->blocked, SIGINT); | ||
644 | |||
645 | recalc_sigpending(); | ||
646 | spin_unlock_irq(¤t->sighand->siglock); | ||
647 | } | ||
648 | |||
649 | static void unblock_signals(sigset_t *old) | ||
650 | { | ||
651 | spin_lock_irq(¤t->sighand->siglock); | ||
652 | current->blocked = *old; | ||
653 | recalc_sigpending(); | ||
654 | spin_unlock_irq(¤t->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 | ||
644 | static inline void coda_waitfor_upcall(struct upc_req *vmp, | 668 | static 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 | */ |
695 | static int coda_upcall(struct coda_sb_info *sbi, | 723 | static 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 | |||
819 | exit: | ||
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 | ||
839 | int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb) | 858 | int 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 | ||