lkml.org 
[lkml]   [2007]   [Oct]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH 2/2] ext2: Avoid rec_len overflow with 64KB block size
    From
    Date
    ext2: Avoid rec_len overflow with 64KB block size

    From: Jan Kara <jack@suse.cz>

    With 64KB blocksize, a directory entry can have size 64KB which does not fit
    into 16 bits we have for entry lenght. So we store 0xffff instead and convert
    value when read from / written to disk.

    Signed-off-by: Jan Kara <jack@suse.cz>
    Signed-off-by: Mingming Cao <cmm@us.ibm.com>
    ---

    fs/ext2/dir.c | 43 +++++++++++++++++++++++++++++++------------
    include/linux/ext2_fs.h | 1 +
    2 files changed, 32 insertions(+), 12 deletions(-)


    diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
    index 2bf49d7..1329bdb 100644
    --- a/fs/ext2/dir.c
    +++ b/fs/ext2/dir.c
    @@ -26,6 +26,24 @@

    typedef struct ext2_dir_entry_2 ext2_dirent;

    +static inline unsigned ext2_rec_len_from_disk(__le16 dlen)
    +{
    + unsigned len = le16_to_cpu(dlen);
    +
    + if (len == EXT2_MAX_REC_LEN)
    + return 1 << 16;
    + return len;
    +}
    +
    +static inline __le16 ext2_rec_len_to_disk(unsigned len)
    +{
    + if (len == (1 << 16))
    + return cpu_to_le16(EXT2_MAX_REC_LEN);
    + else if (len > (1 << 16))
    + BUG();
    + return cpu_to_le16(len);
    +}
    +
    /*
    * ext2 uses block-sized chunks. Arguably, sector-sized ones would be
    * more robust, but we have what we have
    @@ -95,7 +113,7 @@ static void ext2_check_page(struct page *page)
    }
    for (offs = 0; offs <= limit - EXT2_DIR_REC_LEN(1); offs += rec_len) {
    p = (ext2_dirent *)(kaddr + offs);
    - rec_len = le16_to_cpu(p->rec_len);
    + rec_len = ext2_rec_len_from_disk(p->rec_len);

    if (rec_len < EXT2_DIR_REC_LEN(1))
    goto Eshort;
    @@ -193,7 +211,8 @@ static inline int ext2_match (int len, const char * const name,
    */
    static inline ext2_dirent *ext2_next_entry(ext2_dirent *p)
    {
    - return (ext2_dirent *)((char*)p + le16_to_cpu(p->rec_len));
    + return (ext2_dirent *)((char*)p +
    + ext2_rec_len_from_disk(p->rec_len));
    }

    static inline unsigned
    @@ -305,7 +324,7 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
    return 0;
    }
    }
    - filp->f_pos += le16_to_cpu(de->rec_len);
    + filp->f_pos += ext2_rec_len_from_disk(de->rec_len);
    }
    ext2_put_page(page);
    }
    @@ -413,7 +432,7 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
    struct page *page, struct inode *inode)
    {
    unsigned from = (char *) de - (char *) page_address(page);
    - unsigned to = from + le16_to_cpu(de->rec_len);
    + unsigned to = from + ext2_rec_len_from_disk(de->rec_len);
    int err;

    lock_page(page);
    @@ -469,7 +488,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
    /* We hit i_size */
    name_len = 0;
    rec_len = chunk_size;
    - de->rec_len = cpu_to_le16(chunk_size);
    + de->rec_len = ext2_rec_len_to_disk(chunk_size);
    de->inode = 0;
    goto got_it;
    }
    @@ -483,7 +502,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
    if (ext2_match (namelen, name, de))
    goto out_unlock;
    name_len = EXT2_DIR_REC_LEN(de->name_len);
    - rec_len = le16_to_cpu(de->rec_len);
    + rec_len = ext2_rec_len_from_disk(de->rec_len);
    if (!de->inode && rec_len >= reclen)
    goto got_it;
    if (rec_len >= name_len + reclen)
    @@ -504,8 +523,8 @@ got_it:
    goto out_unlock;
    if (de->inode) {
    ext2_dirent *de1 = (ext2_dirent *) ((char *) de + name_len);
    - de1->rec_len = cpu_to_le16(rec_len - name_len);
    - de->rec_len = cpu_to_le16(name_len);
    + de1->rec_len = ext2_rec_len_to_disk(rec_len - name_len);
    + de->rec_len = ext2_rec_len_to_disk(name_len);
    de = de1;
    }
    de->name_len = namelen;
    @@ -536,7 +555,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
    struct inode *inode = mapping->host;
    char *kaddr = page_address(page);
    unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);
    - unsigned to = ((char*)dir - kaddr) + le16_to_cpu(dir->rec_len);
    + unsigned to = ((char*)dir - kaddr) + ext2_rec_len_from_disk(dir->rec_len);
    ext2_dirent * pde = NULL;
    ext2_dirent * de = (ext2_dirent *) (kaddr + from);
    int err;
    @@ -557,7 +576,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
    err = mapping->a_ops->prepare_write(NULL, page, from, to);
    BUG_ON(err);
    if (pde)
    - pde->rec_len = cpu_to_le16(to-from);
    + pde->rec_len = ext2_rec_len_to_disk(to-from);
    dir->inode = 0;
    err = ext2_commit_chunk(page, from, to);
    inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
    @@ -591,14 +610,14 @@ int ext2_make_empty(struct inode *inode, struct inode *parent)
    memset(kaddr, 0, chunk_size);
    de = (struct ext2_dir_entry_2 *)kaddr;
    de->name_len = 1;
    - de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(1));
    + de->rec_len = ext2_rec_len_to_disk(EXT2_DIR_REC_LEN(1));
    memcpy (de->name, ".\0\0", 4);
    de->inode = cpu_to_le32(inode->i_ino);
    ext2_set_de_type (de, inode);

    de = (struct ext2_dir_entry_2 *)(kaddr + EXT2_DIR_REC_LEN(1));
    de->name_len = 2;
    - de->rec_len = cpu_to_le16(chunk_size - EXT2_DIR_REC_LEN(1));
    + de->rec_len = ext2_rec_len_to_disk(chunk_size - EXT2_DIR_REC_LEN(1));
    de->inode = cpu_to_le32(parent->i_ino);
    memcpy (de->name, "..\0", 4);
    ext2_set_de_type (de, inode);
    diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
    index 910a705..41063d5 100644
    --- a/include/linux/ext2_fs.h
    +++ b/include/linux/ext2_fs.h
    @@ -557,5 +557,6 @@ enum {
    #define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
    #define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
    ~EXT2_DIR_ROUND)
    +#define EXT2_MAX_REC_LEN ((1<<16)-1)

    #endif /* _LINUX_EXT2_FS_H */

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-10-02 02:53    [W:0.038 / U:32.464 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site