diff options
Diffstat (limited to 'fs/coda/dir.c')
-rw-r--r-- | fs/coda/dir.c | 286 |
1 files changed, 140 insertions, 146 deletions
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 | } |