|
|
|
@ -327,26 +327,23 @@ int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header, |
|
|
|
|
return is_bad; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir, |
|
|
|
|
static bool omfs_fill_chain(struct inode *dir, struct dir_context *ctx, |
|
|
|
|
u64 fsblock, int hindex) |
|
|
|
|
{ |
|
|
|
|
struct inode *dir = file_inode(filp); |
|
|
|
|
struct buffer_head *bh; |
|
|
|
|
struct omfs_inode *oi; |
|
|
|
|
u64 self; |
|
|
|
|
int res = 0; |
|
|
|
|
unsigned char d_type; |
|
|
|
|
|
|
|
|
|
/* follow chain in this bucket */ |
|
|
|
|
while (fsblock != ~0) { |
|
|
|
|
bh = omfs_bread(dir->i_sb, fsblock); |
|
|
|
|
struct buffer_head *bh = omfs_bread(dir->i_sb, fsblock); |
|
|
|
|
struct omfs_inode *oi; |
|
|
|
|
u64 self; |
|
|
|
|
unsigned char d_type; |
|
|
|
|
|
|
|
|
|
if (!bh) |
|
|
|
|
goto out; |
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
oi = (struct omfs_inode *) bh->b_data; |
|
|
|
|
if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, fsblock)) { |
|
|
|
|
brelse(bh); |
|
|
|
|
goto out; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
self = fsblock; |
|
|
|
@ -361,15 +358,16 @@ static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir, |
|
|
|
|
|
|
|
|
|
d_type = (oi->i_type == OMFS_DIR) ? DT_DIR : DT_REG; |
|
|
|
|
|
|
|
|
|
res = filldir(dirent, oi->i_name, strnlen(oi->i_name, |
|
|
|
|
OMFS_NAMELEN), filp->f_pos, self, d_type); |
|
|
|
|
if (!dir_emit(ctx, oi->i_name, |
|
|
|
|
strnlen(oi->i_name, OMFS_NAMELEN), |
|
|
|
|
self, d_type)) { |
|
|
|
|
brelse(bh); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
brelse(bh); |
|
|
|
|
if (res < 0) |
|
|
|
|
break; |
|
|
|
|
filp->f_pos++; |
|
|
|
|
ctx->pos++; |
|
|
|
|
} |
|
|
|
|
out: |
|
|
|
|
return res; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry, |
|
|
|
@ -403,60 +401,44 @@ out: |
|
|
|
|
return err; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir) |
|
|
|
|
static int omfs_readdir(struct file *file, struct dir_context *ctx) |
|
|
|
|
{ |
|
|
|
|
struct inode *dir = file_inode(filp); |
|
|
|
|
struct inode *dir = file_inode(file); |
|
|
|
|
struct buffer_head *bh; |
|
|
|
|
loff_t offset, res; |
|
|
|
|
__be64 *p; |
|
|
|
|
unsigned int hchain, hindex; |
|
|
|
|
int nbuckets; |
|
|
|
|
u64 fsblock; |
|
|
|
|
int ret = -EINVAL; |
|
|
|
|
|
|
|
|
|
if (filp->f_pos >> 32) |
|
|
|
|
goto success; |
|
|
|
|
|
|
|
|
|
switch ((unsigned long) filp->f_pos) { |
|
|
|
|
case 0: |
|
|
|
|
if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0) |
|
|
|
|
goto success; |
|
|
|
|
filp->f_pos++; |
|
|
|
|
/* fall through */ |
|
|
|
|
case 1: |
|
|
|
|
if (filldir(dirent, "..", 2, 1, |
|
|
|
|
parent_ino(filp->f_dentry), DT_DIR) < 0) |
|
|
|
|
goto success; |
|
|
|
|
filp->f_pos = 1 << 20; |
|
|
|
|
/* fall through */ |
|
|
|
|
|
|
|
|
|
if (ctx->pos >> 32) |
|
|
|
|
return -EINVAL; |
|
|
|
|
|
|
|
|
|
if (ctx->pos < 1 << 20) { |
|
|
|
|
if (!dir_emit_dots(file, ctx)) |
|
|
|
|
return 0; |
|
|
|
|
ctx->pos = 1 << 20; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
nbuckets = (dir->i_size - OMFS_DIR_START) / 8; |
|
|
|
|
|
|
|
|
|
/* high 12 bits store bucket + 1 and low 20 bits store hash index */ |
|
|
|
|
hchain = (filp->f_pos >> 20) - 1; |
|
|
|
|
hindex = filp->f_pos & 0xfffff; |
|
|
|
|
hchain = (ctx->pos >> 20) - 1; |
|
|
|
|
hindex = ctx->pos & 0xfffff; |
|
|
|
|
|
|
|
|
|
bh = omfs_bread(dir->i_sb, dir->i_ino); |
|
|
|
|
if (!bh) |
|
|
|
|
goto out; |
|
|
|
|
return -EINVAL; |
|
|
|
|
|
|
|
|
|
offset = OMFS_DIR_START + hchain * 8; |
|
|
|
|
p = (__be64 *)(bh->b_data + OMFS_DIR_START) + hchain; |
|
|
|
|
|
|
|
|
|
for (; hchain < nbuckets; hchain++, offset += 8) { |
|
|
|
|
fsblock = be64_to_cpu(*((__be64 *) &bh->b_data[offset])); |
|
|
|
|
|
|
|
|
|
res = omfs_fill_chain(filp, dirent, filldir, fsblock, hindex); |
|
|
|
|
hindex = 0; |
|
|
|
|
if (res < 0) |
|
|
|
|
for (; hchain < nbuckets; hchain++) { |
|
|
|
|
__u64 fsblock = be64_to_cpu(*p++); |
|
|
|
|
if (!omfs_fill_chain(dir, ctx, fsblock, hindex)) |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
filp->f_pos = (hchain+2) << 20; |
|
|
|
|
hindex = 0; |
|
|
|
|
ctx->pos = (hchain+2) << 20; |
|
|
|
|
} |
|
|
|
|
brelse(bh); |
|
|
|
|
success: |
|
|
|
|
ret = 0; |
|
|
|
|
out: |
|
|
|
|
return ret; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const struct inode_operations omfs_dir_inops = { |
|
|
|
@ -470,6 +452,6 @@ const struct inode_operations omfs_dir_inops = { |
|
|
|
|
|
|
|
|
|
const struct file_operations omfs_dir_operations = { |
|
|
|
|
.read = generic_read_dir, |
|
|
|
|
.readdir = omfs_readdir, |
|
|
|
|
.iterate = omfs_readdir, |
|
|
|
|
.llseek = generic_file_llseek, |
|
|
|
|
}; |
|
|
|
|