|
|
|
@ -1761,11 +1761,10 @@ bail: |
|
|
|
|
|
|
|
|
|
static int ocfs2_dir_foreach_blk_id(struct inode *inode, |
|
|
|
|
u64 *f_version, |
|
|
|
|
loff_t *f_pos, void *priv, |
|
|
|
|
filldir_t filldir, int *filldir_err) |
|
|
|
|
struct dir_context *ctx) |
|
|
|
|
{ |
|
|
|
|
int ret, i, filldir_ret; |
|
|
|
|
unsigned long offset = *f_pos; |
|
|
|
|
int ret, i; |
|
|
|
|
unsigned long offset = ctx->pos; |
|
|
|
|
struct buffer_head *di_bh = NULL; |
|
|
|
|
struct ocfs2_dinode *di; |
|
|
|
|
struct ocfs2_inline_data *data; |
|
|
|
@ -1781,8 +1780,7 @@ static int ocfs2_dir_foreach_blk_id(struct inode *inode, |
|
|
|
|
di = (struct ocfs2_dinode *)di_bh->b_data; |
|
|
|
|
data = &di->id2.i_data; |
|
|
|
|
|
|
|
|
|
while (*f_pos < i_size_read(inode)) { |
|
|
|
|
revalidate: |
|
|
|
|
while (ctx->pos < i_size_read(inode)) { |
|
|
|
|
/* If the dir block has changed since the last call to
|
|
|
|
|
* readdir(2), then we might be pointing to an invalid |
|
|
|
|
* dirent right now. Scan from the start of the block |
|
|
|
@ -1802,50 +1800,31 @@ revalidate: |
|
|
|
|
break; |
|
|
|
|
i += le16_to_cpu(de->rec_len); |
|
|
|
|
} |
|
|
|
|
*f_pos = offset = i; |
|
|
|
|
ctx->pos = offset = i; |
|
|
|
|
*f_version = inode->i_version; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
de = (struct ocfs2_dir_entry *) (data->id_data + *f_pos); |
|
|
|
|
if (!ocfs2_check_dir_entry(inode, de, di_bh, *f_pos)) { |
|
|
|
|
de = (struct ocfs2_dir_entry *) (data->id_data + ctx->pos); |
|
|
|
|
if (!ocfs2_check_dir_entry(inode, de, di_bh, ctx->pos)) { |
|
|
|
|
/* On error, skip the f_pos to the end. */ |
|
|
|
|
*f_pos = i_size_read(inode); |
|
|
|
|
goto out; |
|
|
|
|
ctx->pos = i_size_read(inode); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
offset += le16_to_cpu(de->rec_len); |
|
|
|
|
if (le64_to_cpu(de->inode)) { |
|
|
|
|
/* We might block in the next section
|
|
|
|
|
* if the data destination is |
|
|
|
|
* currently swapped out. So, use a |
|
|
|
|
* version stamp to detect whether or |
|
|
|
|
* not the directory has been modified |
|
|
|
|
* during the copy operation. |
|
|
|
|
*/ |
|
|
|
|
u64 version = *f_version; |
|
|
|
|
unsigned char d_type = DT_UNKNOWN; |
|
|
|
|
|
|
|
|
|
if (de->file_type < OCFS2_FT_MAX) |
|
|
|
|
d_type = ocfs2_filetype_table[de->file_type]; |
|
|
|
|
|
|
|
|
|
filldir_ret = filldir(priv, de->name, |
|
|
|
|
de->name_len, |
|
|
|
|
*f_pos, |
|
|
|
|
le64_to_cpu(de->inode), |
|
|
|
|
d_type); |
|
|
|
|
if (filldir_ret) { |
|
|
|
|
if (filldir_err) |
|
|
|
|
*filldir_err = filldir_ret; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
if (version != *f_version) |
|
|
|
|
goto revalidate; |
|
|
|
|
if (!dir_emit(ctx, de->name, de->name_len, |
|
|
|
|
le64_to_cpu(de->inode), d_type)) |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
*f_pos += le16_to_cpu(de->rec_len); |
|
|
|
|
ctx->pos += le16_to_cpu(de->rec_len); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
out: |
|
|
|
|
brelse(di_bh); |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1855,27 +1834,26 @@ out: |
|
|
|
|
*/ |
|
|
|
|
static int ocfs2_dir_foreach_blk_el(struct inode *inode, |
|
|
|
|
u64 *f_version, |
|
|
|
|
loff_t *f_pos, void *priv, |
|
|
|
|
filldir_t filldir, int *filldir_err) |
|
|
|
|
struct dir_context *ctx, |
|
|
|
|
bool persist) |
|
|
|
|
{ |
|
|
|
|
int error = 0; |
|
|
|
|
unsigned long offset, blk, last_ra_blk = 0; |
|
|
|
|
int i, stored; |
|
|
|
|
int i; |
|
|
|
|
struct buffer_head * bh, * tmp; |
|
|
|
|
struct ocfs2_dir_entry * de; |
|
|
|
|
struct super_block * sb = inode->i_sb; |
|
|
|
|
unsigned int ra_sectors = 16; |
|
|
|
|
int stored = 0; |
|
|
|
|
|
|
|
|
|
stored = 0; |
|
|
|
|
bh = NULL; |
|
|
|
|
|
|
|
|
|
offset = (*f_pos) & (sb->s_blocksize - 1); |
|
|
|
|
offset = ctx->pos & (sb->s_blocksize - 1); |
|
|
|
|
|
|
|
|
|
while (!error && !stored && *f_pos < i_size_read(inode)) { |
|
|
|
|
blk = (*f_pos) >> sb->s_blocksize_bits; |
|
|
|
|
while (ctx->pos < i_size_read(inode)) { |
|
|
|
|
blk = ctx->pos >> sb->s_blocksize_bits; |
|
|
|
|
if (ocfs2_read_dir_block(inode, blk, &bh, 0)) { |
|
|
|
|
/* Skip the corrupt dirblock and keep trying */ |
|
|
|
|
*f_pos += sb->s_blocksize - offset; |
|
|
|
|
ctx->pos += sb->s_blocksize - offset; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1897,7 +1875,6 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode, |
|
|
|
|
ra_sectors = 8; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
revalidate: |
|
|
|
|
/* If the dir block has changed since the last call to
|
|
|
|
|
* readdir(2), then we might be pointing to an invalid |
|
|
|
|
* dirent right now. Scan from the start of the block |
|
|
|
@ -1917,93 +1894,64 @@ revalidate: |
|
|
|
|
i += le16_to_cpu(de->rec_len); |
|
|
|
|
} |
|
|
|
|
offset = i; |
|
|
|
|
*f_pos = ((*f_pos) & ~(sb->s_blocksize - 1)) |
|
|
|
|
ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1)) |
|
|
|
|
| offset; |
|
|
|
|
*f_version = inode->i_version; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while (!error && *f_pos < i_size_read(inode) |
|
|
|
|
while (ctx->pos < i_size_read(inode) |
|
|
|
|
&& offset < sb->s_blocksize) { |
|
|
|
|
de = (struct ocfs2_dir_entry *) (bh->b_data + offset); |
|
|
|
|
if (!ocfs2_check_dir_entry(inode, de, bh, offset)) { |
|
|
|
|
/* On error, skip the f_pos to the
|
|
|
|
|
next block. */ |
|
|
|
|
*f_pos = ((*f_pos) | (sb->s_blocksize - 1)) + 1; |
|
|
|
|
ctx->pos = (ctx->pos | (sb->s_blocksize - 1)) + 1; |
|
|
|
|
brelse(bh); |
|
|
|
|
goto out; |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
offset += le16_to_cpu(de->rec_len); |
|
|
|
|
if (le64_to_cpu(de->inode)) { |
|
|
|
|
/* We might block in the next section
|
|
|
|
|
* if the data destination is |
|
|
|
|
* currently swapped out. So, use a |
|
|
|
|
* version stamp to detect whether or |
|
|
|
|
* not the directory has been modified |
|
|
|
|
* during the copy operation. |
|
|
|
|
*/ |
|
|
|
|
unsigned long version = *f_version; |
|
|
|
|
unsigned char d_type = DT_UNKNOWN; |
|
|
|
|
|
|
|
|
|
if (de->file_type < OCFS2_FT_MAX) |
|
|
|
|
d_type = ocfs2_filetype_table[de->file_type]; |
|
|
|
|
error = filldir(priv, de->name, |
|
|
|
|
if (!dir_emit(ctx, de->name, |
|
|
|
|
de->name_len, |
|
|
|
|
*f_pos, |
|
|
|
|
le64_to_cpu(de->inode), |
|
|
|
|
d_type); |
|
|
|
|
if (error) { |
|
|
|
|
if (filldir_err) |
|
|
|
|
*filldir_err = error; |
|
|
|
|
break; |
|
|
|
|
d_type)) { |
|
|
|
|
brelse(bh); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
if (version != *f_version) |
|
|
|
|
goto revalidate; |
|
|
|
|
stored ++; |
|
|
|
|
stored++; |
|
|
|
|
} |
|
|
|
|
*f_pos += le16_to_cpu(de->rec_len); |
|
|
|
|
offset += le16_to_cpu(de->rec_len); |
|
|
|
|
ctx->pos += le16_to_cpu(de->rec_len); |
|
|
|
|
} |
|
|
|
|
offset = 0; |
|
|
|
|
brelse(bh); |
|
|
|
|
bh = NULL; |
|
|
|
|
if (!persist && stored) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
stored = 0; |
|
|
|
|
out: |
|
|
|
|
return stored; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int ocfs2_dir_foreach_blk(struct inode *inode, u64 *f_version, |
|
|
|
|
loff_t *f_pos, void *priv, filldir_t filldir, |
|
|
|
|
int *filldir_err) |
|
|
|
|
struct dir_context *ctx, |
|
|
|
|
bool persist) |
|
|
|
|
{ |
|
|
|
|
if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) |
|
|
|
|
return ocfs2_dir_foreach_blk_id(inode, f_version, f_pos, priv, |
|
|
|
|
filldir, filldir_err); |
|
|
|
|
|
|
|
|
|
return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir, |
|
|
|
|
filldir_err); |
|
|
|
|
return ocfs2_dir_foreach_blk_id(inode, f_version, ctx); |
|
|
|
|
return ocfs2_dir_foreach_blk_el(inode, f_version, ctx, persist); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is intended to be called from inside other kernel functions, |
|
|
|
|
* so we fake some arguments. |
|
|
|
|
*/ |
|
|
|
|
int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv, |
|
|
|
|
filldir_t filldir) |
|
|
|
|
int ocfs2_dir_foreach(struct inode *inode, struct dir_context *ctx) |
|
|
|
|
{ |
|
|
|
|
int ret = 0, filldir_err = 0; |
|
|
|
|
u64 version = inode->i_version; |
|
|
|
|
|
|
|
|
|
while (*f_pos < i_size_read(inode)) { |
|
|
|
|
ret = ocfs2_dir_foreach_blk(inode, &version, f_pos, priv, |
|
|
|
|
filldir, &filldir_err); |
|
|
|
|
if (ret || filldir_err) |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (ret > 0) |
|
|
|
|
ret = -EIO; |
|
|
|
|
|
|
|
|
|
ocfs2_dir_foreach_blk(inode, &version, ctx, true); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -2011,15 +1959,15 @@ int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv, |
|
|
|
|
* ocfs2_readdir() |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir) |
|
|
|
|
int ocfs2_readdir(struct file *file, struct dir_context *ctx) |
|
|
|
|
{ |
|
|
|
|
int error = 0; |
|
|
|
|
struct inode *inode = file_inode(filp); |
|
|
|
|
struct inode *inode = file_inode(file); |
|
|
|
|
int lock_level = 0; |
|
|
|
|
|
|
|
|
|
trace_ocfs2_readdir((unsigned long long)OCFS2_I(inode)->ip_blkno); |
|
|
|
|
|
|
|
|
|
error = ocfs2_inode_lock_atime(inode, filp->f_path.mnt, &lock_level); |
|
|
|
|
error = ocfs2_inode_lock_atime(inode, file->f_path.mnt, &lock_level); |
|
|
|
|
if (lock_level && error >= 0) { |
|
|
|
|
/* We release EX lock which used to update atime
|
|
|
|
|
* and get PR lock again to reduce contention |
|
|
|
@ -2035,8 +1983,7 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir) |
|
|
|
|
goto bail_nolock; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos, |
|
|
|
|
dirent, filldir, NULL); |
|
|
|
|
error = ocfs2_dir_foreach_blk(inode, &file->f_version, ctx, false); |
|
|
|
|
|
|
|
|
|
ocfs2_inode_unlock(inode, lock_level); |
|
|
|
|
if (error) |
|
|
|
@ -2120,6 +2067,7 @@ bail: |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct ocfs2_empty_dir_priv { |
|
|
|
|
struct dir_context ctx; |
|
|
|
|
unsigned seen_dot; |
|
|
|
|
unsigned seen_dot_dot; |
|
|
|
|
unsigned seen_other; |
|
|
|
@ -2204,8 +2152,9 @@ out: |
|
|
|
|
int ocfs2_empty_dir(struct inode *inode) |
|
|
|
|
{ |
|
|
|
|
int ret; |
|
|
|
|
loff_t start = 0; |
|
|
|
|
struct ocfs2_empty_dir_priv priv; |
|
|
|
|
struct ocfs2_empty_dir_priv priv = { |
|
|
|
|
.ctx.actor = ocfs2_empty_dir_filldir |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
memset(&priv, 0, sizeof(priv)); |
|
|
|
|
|
|
|
|
@ -2219,7 +2168,7 @@ int ocfs2_empty_dir(struct inode *inode) |
|
|
|
|
*/ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir); |
|
|
|
|
ret = ocfs2_dir_foreach(inode, &priv.ctx); |
|
|
|
|
if (ret) |
|
|
|
|
mlog_errno(ret); |
|
|
|
|
|
|
|
|
|