diff options
Diffstat (limited to 'fs/omfs/dir.c')
-rw-r--r-- | fs/omfs/dir.c | 94 |
1 files changed, 38 insertions, 56 deletions
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c index acbaebcad3a8..1b8e9e8405b2 100644 --- a/fs/omfs/dir.c +++ b/fs/omfs/dir.c | |||
@@ -327,26 +327,23 @@ int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header, | |||
327 | return is_bad; | 327 | return is_bad; |
328 | } | 328 | } |
329 | 329 | ||
330 | static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir, | 330 | static bool omfs_fill_chain(struct inode *dir, struct dir_context *ctx, |
331 | u64 fsblock, int hindex) | 331 | u64 fsblock, int hindex) |
332 | { | 332 | { |
333 | struct inode *dir = file_inode(filp); | ||
334 | struct buffer_head *bh; | ||
335 | struct omfs_inode *oi; | ||
336 | u64 self; | ||
337 | int res = 0; | ||
338 | unsigned char d_type; | ||
339 | |||
340 | /* follow chain in this bucket */ | 333 | /* follow chain in this bucket */ |
341 | while (fsblock != ~0) { | 334 | while (fsblock != ~0) { |
342 | bh = omfs_bread(dir->i_sb, fsblock); | 335 | struct buffer_head *bh = omfs_bread(dir->i_sb, fsblock); |
336 | struct omfs_inode *oi; | ||
337 | u64 self; | ||
338 | unsigned char d_type; | ||
339 | |||
343 | if (!bh) | 340 | if (!bh) |
344 | goto out; | 341 | return true; |
345 | 342 | ||
346 | oi = (struct omfs_inode *) bh->b_data; | 343 | oi = (struct omfs_inode *) bh->b_data; |
347 | if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, fsblock)) { | 344 | if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, fsblock)) { |
348 | brelse(bh); | 345 | brelse(bh); |
349 | goto out; | 346 | return true; |
350 | } | 347 | } |
351 | 348 | ||
352 | self = fsblock; | 349 | self = fsblock; |
@@ -361,15 +358,16 @@ static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir, | |||
361 | 358 | ||
362 | d_type = (oi->i_type == OMFS_DIR) ? DT_DIR : DT_REG; | 359 | d_type = (oi->i_type == OMFS_DIR) ? DT_DIR : DT_REG; |
363 | 360 | ||
364 | res = filldir(dirent, oi->i_name, strnlen(oi->i_name, | 361 | if (!dir_emit(ctx, oi->i_name, |
365 | OMFS_NAMELEN), filp->f_pos, self, d_type); | 362 | strnlen(oi->i_name, OMFS_NAMELEN), |
363 | self, d_type)) { | ||
364 | brelse(bh); | ||
365 | return false; | ||
366 | } | ||
366 | brelse(bh); | 367 | brelse(bh); |
367 | if (res < 0) | 368 | ctx->pos++; |
368 | break; | ||
369 | filp->f_pos++; | ||
370 | } | 369 | } |
371 | out: | 370 | return true; |
372 | return res; | ||
373 | } | 371 | } |
374 | 372 | ||
375 | static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry, | 373 | static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry, |
@@ -403,60 +401,44 @@ out: | |||
403 | return err; | 401 | return err; |
404 | } | 402 | } |
405 | 403 | ||
406 | static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | 404 | static int omfs_readdir(struct file *file, struct dir_context *ctx) |
407 | { | 405 | { |
408 | struct inode *dir = file_inode(filp); | 406 | struct inode *dir = file_inode(file); |
409 | struct buffer_head *bh; | 407 | struct buffer_head *bh; |
410 | loff_t offset, res; | 408 | __be64 *p; |
411 | unsigned int hchain, hindex; | 409 | unsigned int hchain, hindex; |
412 | int nbuckets; | 410 | int nbuckets; |
413 | u64 fsblock; | 411 | |
414 | int ret = -EINVAL; | 412 | if (ctx->pos >> 32) |
415 | 413 | return -EINVAL; | |
416 | if (filp->f_pos >> 32) | 414 | |
417 | goto success; | 415 | if (ctx->pos < 1 << 20) { |
418 | 416 | if (!dir_emit_dots(file, ctx)) | |
419 | switch ((unsigned long) filp->f_pos) { | 417 | return 0; |
420 | case 0: | 418 | ctx->pos = 1 << 20; |
421 | if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0) | ||
422 | goto success; | ||
423 | filp->f_pos++; | ||
424 | /* fall through */ | ||
425 | case 1: | ||
426 | if (filldir(dirent, "..", 2, 1, | ||
427 | parent_ino(filp->f_dentry), DT_DIR) < 0) | ||
428 | goto success; | ||
429 | filp->f_pos = 1 << 20; | ||
430 | /* fall through */ | ||
431 | } | 419 | } |
432 | 420 | ||
433 | nbuckets = (dir->i_size - OMFS_DIR_START) / 8; | 421 | nbuckets = (dir->i_size - OMFS_DIR_START) / 8; |
434 | 422 | ||
435 | /* high 12 bits store bucket + 1 and low 20 bits store hash index */ | 423 | /* high 12 bits store bucket + 1 and low 20 bits store hash index */ |
436 | hchain = (filp->f_pos >> 20) - 1; | 424 | hchain = (ctx->pos >> 20) - 1; |
437 | hindex = filp->f_pos & 0xfffff; | 425 | hindex = ctx->pos & 0xfffff; |
438 | 426 | ||
439 | bh = omfs_bread(dir->i_sb, dir->i_ino); | 427 | bh = omfs_bread(dir->i_sb, dir->i_ino); |
440 | if (!bh) | 428 | if (!bh) |
441 | goto out; | 429 | return -EINVAL; |
442 | 430 | ||
443 | offset = OMFS_DIR_START + hchain * 8; | 431 | p = (__be64 *)(bh->b_data + OMFS_DIR_START) + hchain; |
444 | 432 | ||
445 | for (; hchain < nbuckets; hchain++, offset += 8) { | 433 | for (; hchain < nbuckets; hchain++) { |
446 | fsblock = be64_to_cpu(*((__be64 *) &bh->b_data[offset])); | 434 | __u64 fsblock = be64_to_cpu(*p++); |
447 | 435 | if (!omfs_fill_chain(dir, ctx, fsblock, hindex)) | |
448 | res = omfs_fill_chain(filp, dirent, filldir, fsblock, hindex); | ||
449 | hindex = 0; | ||
450 | if (res < 0) | ||
451 | break; | 436 | break; |
452 | 437 | hindex = 0; | |
453 | filp->f_pos = (hchain+2) << 20; | 438 | ctx->pos = (hchain+2) << 20; |
454 | } | 439 | } |
455 | brelse(bh); | 440 | brelse(bh); |
456 | success: | 441 | return 0; |
457 | ret = 0; | ||
458 | out: | ||
459 | return ret; | ||
460 | } | 442 | } |
461 | 443 | ||
462 | const struct inode_operations omfs_dir_inops = { | 444 | const struct inode_operations omfs_dir_inops = { |
@@ -470,6 +452,6 @@ const struct inode_operations omfs_dir_inops = { | |||
470 | 452 | ||
471 | const struct file_operations omfs_dir_operations = { | 453 | const struct file_operations omfs_dir_operations = { |
472 | .read = generic_read_dir, | 454 | .read = generic_read_dir, |
473 | .readdir = omfs_readdir, | 455 | .iterate = omfs_readdir, |
474 | .llseek = generic_file_llseek, | 456 | .llseek = generic_file_llseek, |
475 | }; | 457 | }; |