diff options
Diffstat (limited to 'fs/ocfs2/dir.c')
-rw-r--r-- | fs/ocfs2/dir.c | 151 |
1 files changed, 50 insertions, 101 deletions
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index f1e1aed8f63..eb760d8acd5 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -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); |