[Bugme-new] [Bug 9171] New: __bread and 2TiB problem

bugme-daemon at bugzilla.kernel.org bugme-daemon at bugzilla.kernel.org
Tue Oct 16 08:47:03 PDT 2007


http://bugzilla.kernel.org/show_bug.cgi?id=9171

           Summary: __bread and 2TiB problem
           Product: IO/Storage
           Version: 2.5
     KernelVersion: 2.6.22
          Platform: All
        OS/Version: Linux
              Tree: Mainline
            Status: NEW
          Severity: normal
          Priority: P1
         Component: Block Layer
        AssignedTo: axboe at kernel.dk
        ReportedBy: shura_mam at mail.ru


Most recent kernel where this bug did not occur:
Distribution: SUSE 10.1 (2.6.18) and Debian (2.6.22)
Hardware Environment:
Software Environment: 
Problem Description:

Steps to reproduce:

Compile the following module and try to mount any device of size > 2TiB.
and you will see the infinite loop
"__find_get_block_slow() failed"

///////////////////////////////////////////////////////////
// This example shows __bread error if block >= 2^32
//
//
///////////////////////////////////////////////////////////

#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/buffer_head.h>
#include <linux/vermagic.h>

#define USE_BREAD "Activate this macros to get the __bread error"

#ifndef USE_BREAD

///////////////////////////////////////////////////////////
// end_bio_io_page
//
//
///////////////////////////////////////////////////////////
static int
end_bio_io_page(
    struct bio *bio,
    unsigned int bytes_done,
    int error
    )
{
  struct page *page = bio->bi_private;
  if (bio->bi_size)
    return 1;

  if (!error)
    SetPageUptodate(page);
  else
    printk(KERN_WARNING "t2tb: error %d reading page\n", error);
  unlock_page(page);
  bio_put(bio);
  return 0;
}


///////////////////////////////////////////////////////////
// t2tb_read_page
//
//
///////////////////////////////////////////////////////////
struct page*
t2tb_read_page(
    struct super_block *sb,
    sector_t sector
    )
{
  struct page *page;
  struct bio *bio;

  page = alloc_page(GFP_KERNEL);
  if ( unlikely(!page) )
    return NULL;

  ClearPageUptodate(page);
  ClearPageDirty(page);
  lock_page(page);

  bio = bio_alloc(GFP_KERNEL, 1);
  if (unlikely(!bio)) {
    __free_page(page);
    return NULL;
  }

  bio->bi_sector  = sector;
  bio->bi_bdev    = sb->s_bdev;
  bio_add_page(bio, page, PAGE_SIZE, 0);

  bio->bi_end_io  = end_bio_io_page;
  bio->bi_private = page;
  bio_get(bio);
  submit_bio( READ_SYNC, bio);
  wait_on_page_locked(page);
  bio_put(bio);
  if (!PageUptodate(page)) {
    __free_page(page);
    return NULL;
  }

  return page;
}


///////////////////////////////////////////////////////////
// t2tb_read
//
//
///////////////////////////////////////////////////////////
static int
t2tb_read(
    struct super_block *sb,
    sector_t sector
    )
{
  struct page* page;
  printk(KERN_NOTICE ": read(0x%llx)\n", sector );

  page = t2tb_read_page( sb, sector );

  if ( NULL == page )
    return -1;

  __free_page( page );
  return 0;
}

#else

///////////////////////////////////////////////////////////
// t2tb_read
//
//
///////////////////////////////////////////////////////////
static int
t2tb_read(
    struct super_block *sb,
    sector_t sector
    )
{
  struct buffer_head* bh;
  printk(KERN_NOTICE ": read(0x%llx)\n", sector );

  bh = __bread( sb->s_bdev, sector, 512 );
  if ( NULL == bh )
    return -1;

  __brelse(bh);
  return 0;
}

#endif



///////////////////////////////////////////////////////////
// t2tb_read_super
//
//
///////////////////////////////////////////////////////////
static int
t2tb_read_super(
    struct super_block * sb,
    void * data,
    int silent
    )
{
  set_blocksize( sb->s_bdev, 512 );
  sb->s_blocksize      = 512;
  sb->s_blocksize_bits = 9;

  printk(KERN_NOTICE "t2tb_read_super: enter\n" );

  t2tb_read( sb, 0 );
  t2tb_read( sb, 0x100000000ull-1 );
  //
  // If 't2tb_read' uses __bread then the next function will never return.
  // Infinite loop at "__find_get_block_slow() failed" occurs
  //
  t2tb_read( sb, 0x100000000ull );

  printk(KERN_NOTICE "t2tb_read_super: exit\n" );

  return -EINVAL;
}


#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
static int
t2tb_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name,
    void *data, struct vfsmount* mnt)
{
  return get_sb_bdev(fs_type, flags, dev_name, data, t2tb_read_super, mnt );
}
#else
static struct super_block *
t2tb_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name,
    void *data)
{
  return get_sb_bdev(fs_type, flags, dev_name, data, t2tb_read_super );
}
#endif

static struct file_system_type t2tb_fs_type = {
    .owner      = THIS_MODULE,
    .name       = "t2tb",
    .get_sb     = t2tb_get_sb,
    .kill_sb    = kill_block_super,
    .fs_flags   = FS_REQUIRES_DEV,
};


MODULE_INFO(vermagic, VERMAGIC_STRING);
struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
    .name = "t2tb",
    .init = init_module,
    .exit = cleanup_module,
};



///////////////////////////////////////////////////////////
// t2tb_init
//
// module init function
///////////////////////////////////////////////////////////
static int
__init t2tb_init(void)
{
  int ret = register_filesystem(&t2tb_fs_type);
  if ( 0 != ret )
    return ret;

  printk(KERN_NOTICE ": t2tb driver loaded\n");
  return 0;
}


///////////////////////////////////////////////////////////
// t2tb_exit
//
// module exit function
///////////////////////////////////////////////////////////
static void
__exit t2tb_exit(void)
{
  unregister_filesystem(&t2tb_fs_type);
  printk(KERN_NOTICE ": t2tb driver unloaded\n");
}

module_init(t2tb_init)
module_exit(t2tb_exit)


-- 
Configure bugmail: http://bugzilla.kernel.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


More information about the Bugme-new mailing list