]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/ext4/dir.c
Merge tag 'for-linus' of git://git.armlinux.org.uk/~rmk/linux-arm
[linux.git] / fs / ext4 / dir.c
index c7843b149a1e877f010904572cfd7662c715e226..9fdd2b269d6172a6856ef0fb98419bf7ed599671 100644 (file)
@@ -33,6 +33,9 @@
 static int ext4_dx_readdir(struct file *, struct dir_context *);
 
 /**
+ * is_dx_dir() - check if a directory is using htree indexing
+ * @inode: directory inode
+ *
  * Check if the given dir-inode refers to an htree-indexed directory
  * (or a directory which could potentially get converted to use htree
  * indexing).
@@ -109,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)) {
@@ -145,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;
 
@@ -155,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);
@@ -176,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;
@@ -192,8 +194,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
 
                /* Check the checksum */
                if (!buffer_verified(bh) &&
-                   !ext4_dirent_csum_verify(inode,
-                               (struct ext4_dir_entry *)bh->b_data)) {
+                   !ext4_dirblock_csum_verify(inode, bh)) {
                        EXT4_ERROR_FILE(file, 0, "directory fails checksum "
                                        "at offset %llu",
                                        (unsigned long long)ctx->pos);
@@ -667,14 +668,15 @@ static int ext4_d_compare(const struct dentry *dentry, unsigned int len,
                          const char *str, const struct qstr *name)
 {
        struct qstr qstr = {.name = str, .len = len };
+       struct inode *inode = dentry->d_parent->d_inode;
 
-       if (!IS_CASEFOLDED(dentry->d_parent->d_inode)) {
+       if (!IS_CASEFOLDED(inode) || !EXT4_SB(inode->i_sb)->s_encoding) {
                if (len != name->len)
                        return -1;
                return memcmp(str, name->name, len);
        }
 
-       return ext4_ci_compare(dentry->d_parent->d_inode, name, &qstr);
+       return ext4_ci_compare(inode, name, &qstr, false);
 }
 
 static int ext4_d_hash(const struct dentry *dentry, struct qstr *str)
@@ -684,7 +686,7 @@ static int ext4_d_hash(const struct dentry *dentry, struct qstr *str)
        unsigned char *norm;
        int len, ret = 0;
 
-       if (!IS_CASEFOLDED(dentry->d_inode))
+       if (!IS_CASEFOLDED(dentry->d_inode) || !um)
                return 0;
 
        norm = kmalloc(PATH_MAX, GFP_ATOMIC);