diff options
Diffstat (limited to 'fs/btrfs/inode.c')
| -rw-r--r-- | fs/btrfs/inode.c | 14 | 
1 files changed, 13 insertions, 1 deletions
| diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5f06eb1f4384..151b7c71b868 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5717,6 +5717,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)  	char *name_ptr;  	int name_len;  	int is_curr = 0;	/* ctx->pos points to the current index? */ +	bool emitted;  	/* FIXME, use a real flag for deciding about the key type */  	if (root->fs_info->tree_root == root) @@ -5745,6 +5746,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)  	if (ret < 0)  		goto err; +	emitted = false;  	while (1) {  		leaf = path->nodes[0];  		slot = path->slots[0]; @@ -5824,6 +5826,7 @@ skip:  			if (over)  				goto nopos; +			emitted = true;  			di_len = btrfs_dir_name_len(leaf, di) +  				 btrfs_dir_data_len(leaf, di) + sizeof(*di);  			di_cur += di_len; @@ -5836,11 +5839,20 @@ next:  	if (key_type == BTRFS_DIR_INDEX_KEY) {  		if (is_curr)  			ctx->pos++; -		ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list); +		ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list, &emitted);  		if (ret)  			goto nopos;  	} +	/* +	 * If we haven't emitted any dir entry, we must not touch ctx->pos as +	 * it was was set to the termination value in previous call. We assume +	 * that "." and ".." were emitted if we reach this point and set the +	 * termination value as well for an empty directory. +	 */ +	if (ctx->pos > 2 && !emitted) +		goto nopos; +  	/* Reached end of directory/root. Bump pos past the last item. */  	ctx->pos++; | 
