aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/fs/ext4/dir.c
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2019-06-20 21:19:02 -0400
committerTheodore Ts'o <tytso@mit.edu>2019-06-20 21:19:02 -0400
commit4e19d6b65fb4fc42e352ce9883649e049da14743 (patch)
tree08f0adf221ba0207d87495464ced7bd8ed1f23d0 /fs/ext4/dir.c
parentjbd2: drop declaration of journal_sync_buffer() (diff)
downloadwireguard-linux-4e19d6b65fb4fc42e352ce9883649e049da14743.tar.xz
wireguard-linux-4e19d6b65fb4fc42e352ce9883649e049da14743.zip
ext4: allow directory holes
The largedir feature was intended to allow ext4 directories to have unmapped directory blocks (e.g., directory holes). And so the released e2fsprogs no longer enforces this for largedir file systems; however, the corresponding change to the kernel-side code was not made. This commit fixes this oversight. Signed-off-by: Theodore Ts'o <tytso@mit.edu> Cc: stable@kernel.org
Diffstat (limited to 'fs/ext4/dir.c')
-rw-r--r--fs/ext4/dir.c19
1 files changed, 9 insertions, 10 deletions
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index 770a1e6d4672..3a77b7affd09 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -112,7 +112,6 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
struct buffer_head *bh = NULL;
- int dir_has_error = 0;
struct fscrypt_str fstr = FSTR_INIT(NULL, 0);
if (IS_ENCRYPTED(inode)) {
@@ -148,8 +147,6 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
return err;
}
- offset = ctx->pos & (sb->s_blocksize - 1);
-
while (ctx->pos < inode->i_size) {
struct ext4_map_blocks map;
@@ -158,9 +155,18 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
goto errout;
}
cond_resched();
+ offset = ctx->pos & (sb->s_blocksize - 1);
map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
map.m_len = 1;
err = ext4_map_blocks(NULL, inode, &map, 0);
+ if (err == 0) {
+ /* m_len should never be zero but let's avoid
+ * an infinite loop if it somehow is */
+ if (map.m_len == 0)
+ map.m_len = 1;
+ ctx->pos += map.m_len * sb->s_blocksize;
+ continue;
+ }
if (err > 0) {
pgoff_t index = map.m_pblk >>
(PAGE_SHIFT - inode->i_blkbits);
@@ -179,13 +185,6 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
}
if (!bh) {
- if (!dir_has_error) {
- EXT4_ERROR_FILE(file, 0,
- "directory contains a "
- "hole at offset %llu",
- (unsigned long long) ctx->pos);
- dir_has_error = 1;
- }
/* corrupt size? Maybe no more blocks to read */
if (ctx->pos > inode->i_blocks << 9)
break;