aboutsummaryrefslogtreecommitdiffstats
path: root/fs/omfs/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/omfs/dir.c')
-rw-r--r--fs/omfs/dir.c94
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
330static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir, 330static 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 }
371out: 370 return true;
372 return res;
373} 371}
374 372
375static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry, 373static 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
406static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir) 404static 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);
456success: 441 return 0;
457 ret = 0;
458out:
459 return ret;
460} 442}
461 443
462const struct inode_operations omfs_dir_inops = { 444const struct inode_operations omfs_dir_inops = {
@@ -470,6 +452,6 @@ const struct inode_operations omfs_dir_inops = {
470 452
471const struct file_operations omfs_dir_operations = { 453const 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};