lkml.org 
[lkml]   [2000]   [Mar]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch/rfc] ramdisk.. final chapter?
    Hi Linus, (and list members)

    The patch below addresses all known functional issues with the ramdisk
    and passes all tests I can think of.

    What it doesn't solve, is a (design?) weakness whereby the ramdisk can
    cause swap looping if it's trying to grow_buffers() to dynamically
    allocate blocks during high memory pressure times. This is exposed
    by swapping madly (ultimate test) to a ramdisk. It passes the test
    just fine iff I populate the ramdisk (dd) prior to mkswap/swapon on
    the device. I'm running the result of make -j3 bzImage MAKE='make -j3'
    with the ramswap being enabled/disabled/enabled repeatedly during build,
    migrating it's content to a lower priority swap partiton and back.

    Changes:

    Unconditionally retrieve/create/populate buffers during rd_request.
    This resolves a problem whereby a ramdisk filled with an fs image
    then wiped and re-filled has files full of zeros. My understanding
    of the buffer cache + page cache == unified cache is too shaky to
    explain this at all. My _impression_ is that the total cache state
    must be stored in the ramdisk (lives in buffer cache portion of total)
    for it to work properly (ie aliases=state problem). This is as shaky
    as explanations come, but that's what I'm trying to do, and it works.
    (Tigran tested/confirmed that it resolves that problem)

    Added igrab()/iput() to protect the ramdisk inodes from prune_icache()
    when ramdisks are present but inactive.

    Added setup option for blocksize when ramdisk is in kernel such that
    options are the same as what's available as a module. This is needed
    if you want to swap to ramdisk when it's in kernel.. a valid way to
    test swap performance on a machine with terrible/old disk drives :)

    Tiny cleanups.

    If anything is horrible from the OS designer viewpoint, punt me in the
    right direction and I'll try to do better. Patch is below.

    Thanks for your time,

    -Mike

    --- linux-2.3.50.virgin/drivers/block/rd.c Fri Mar 3 06:28:01 2000
    +++ linux-2.3.49.test/drivers/block/rd.c Wed Mar 8 16:36:24 2000
    @@ -99,6 +99,7 @@
    static int rd_blocksizes[NUM_RAMDISKS]; /* Size of 1024 byte blocks :) */
    static int rd_kbsize[NUM_RAMDISKS]; /* Size in blocks of 1024 bytes */
    static devfs_handle_t devfs_handle = NULL;
    +static struct inode *rd_inode[NUM_RAMDISKS]; /* Protected device inodes */

    /*
    * Parameters for the boot-loading of the RAM disk. These are set by
    @@ -169,11 +170,18 @@
    return ramdisk_size(str);
    }

    +static int __init ramdisk_blocksize(char *str)
    +{
    + rd_blocksize = simple_strtol(str,NULL,0);
    + return 1;
    +}
    +
    __setup("ramdisk_start=", ramdisk_start_setup);
    __setup("load_ramdisk=", load_ramdisk);
    __setup("prompt_ramdisk=", prompt_ramdisk);
    __setup("ramdisk=", ramdisk_size);
    __setup("ramdisk_size=", ramdisk_size2);
    +__setup("ramdisk_blocksize=", ramdisk_blocksize);

    #endif

    @@ -216,67 +224,16 @@
    goto repeat;
    }

    - /*
    - * This has become somewhat more complicated with the addition of
    - * the page cache. The problem is that in some cases the furnished
    - * buffer is "real", i.e., part of the existing ramdisk, while in
    - * others it is "unreal", e.g., part of a page. In the first case
    - * not much needs to be done, while in the second, some kind of
    - * transfer is needed.
    - *
    - * The two cases are distinguished here by checking whether the
    - * real buffer is already in the buffer cache, and whether it is
    - * the same as the one supplied.
    - *
    - * There are three cases with read/write to consider:
    - *
    - * 1. Supplied buffer matched one in the buffer cache:
    - * Read - Clear the buffer, as it wasn't already valid.
    - * Write - Mark the buffer as "Protected".
    - *
    - * 2. Supplied buffer mismatched one in the buffer cache:
    - * Read - Copy the data from the buffer cache entry.
    - * Write - Copy the data to the buffer cache entry.
    - *
    - * 3 No buffer cache entry existed:
    - * Read - Clear the supplied buffer, but do not create a real
    - * one.
    - * Write - Create a real buffer, copy the data to it, and mark
    - * it as "Protected".
    - *
    - * NOTE: There seems to be some schizophrenia here - the logic
    - * using "len" seems to assume arbitrary request lengths, while
    - * the "protect" logic assumes a single buffer cache entry.
    - * This seems to be left over from the ancient contiguous ramdisk
    - * logic.
    - */
    -
    sbh = CURRENT->bh;
    - rbh = get_hash_table(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
    - if (sbh == rbh) {
    - if (CURRENT->cmd == READ)
    - memset(CURRENT->buffer, 1, len);
    - } else if (rbh) {
    - if (CURRENT->cmd == READ)
    + rbh = getblk(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
    + if (CURRENT->cmd == READ) {
    + if (sbh != rbh)
    memcpy(CURRENT->buffer, rbh->b_data, rbh->b_size);
    - else
    + } else
    + if (sbh != rbh)
    memcpy(rbh->b_data, CURRENT->buffer, rbh->b_size);
    - } else { /* !rbh */
    - if (CURRENT->cmd == READ)
    - memset(sbh->b_data, 2, len);
    - else {
    - rbh = getblk(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
    - if (rbh)
    - memcpy(rbh->b_data, CURRENT->buffer,
    - rbh->b_size);
    - else
    - BUG(); /* No buffer, what to do here? */
    - }
    - }
    - if (rbh) {
    - mark_buffer_protected(rbh);
    - brelse(rbh);
    - }
    + mark_buffer_protected(rbh);
    + brelse(rbh);

    end_request(1);
    goto repeat;
    @@ -372,6 +329,14 @@
    if (DEVICE_NR(inode->i_rdev) >= NUM_RAMDISKS)
    return -ENXIO;

    + /*
    + * Immunize device against invalidate_buffers() and prune_icache().
    + */
    + if (rd_inode[DEVICE_NR(inode->i_rdev)] == NULL) {
    + if((rd_inode[DEVICE_NR(inode->i_rdev)] = igrab(inode)) != NULL)
    + atomic_inc(&rd_inode[DEVICE_NR(inode->i_rdev)]->i_bdev->bd_openers);
    + }
    +
    MOD_INC_USE_COUNT;

    return 0;
    @@ -389,24 +354,31 @@
    ioctl: rd_ioctl,
    };

    +#ifdef MODULE
    /* Before freeing the module, invalidate all of the protected buffers! */
    static void __exit rd_cleanup (void)
    {
    int i;

    for (i = 0 ; i < NUM_RAMDISKS; i++) {
    - struct block_device *bdev;
    - bdev = bdget(kdev_t_to_nr(MKDEV(MAJOR_NR,i)));
    - atomic_dec(&bdev->bd_openers);
    + if (rd_inode[i]) {
    + /* withdraw invalidate_buffers() and prune_icache() immunity */
    + atomic_dec(&rd_inode[i]->i_bdev->bd_openers);
    + /* remove stale pointer to module address space */
    + rd_inode[i]->i_bdev->bd_op = NULL;
    + iput(rd_inode[i]);
    + }
    destroy_buffers(MKDEV(MAJOR_NR, i));
    }

    devfs_unregister (devfs_handle);
    unregister_blkdev( MAJOR_NR, "ramdisk" );
    blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
    + hardsect_size[MAJOR_NR] = NULL;
    blksize_size[MAJOR_NR] = NULL;
    blk_size[MAJOR_NR] = NULL;
    }
    +#endif

    /* This is the registration and initialization section of the RAM disk driver */
    int __init rd_init (void)
    @@ -441,21 +413,16 @@
    S_IFBLK | S_IRUSR | S_IWUSR, 0, 0,
    &fd_fops, NULL);

    - hardsect_size[MAJOR_NR] = rd_hardsec; /* Size of the RAM disk blocks */
    - blksize_size[MAJOR_NR] = rd_blocksizes; /* Avoid set_blocksize() check */
    -
    - for (i = 0; i < NUM_RAMDISKS; i++) {
    - struct block_device *bdev;
    + for (i = 0; i < NUM_RAMDISKS; i++)
    register_disk(NULL, MKDEV(MAJOR_NR,i), 1, &fd_fops, rd_size<<1);
    - bdev = bdget(kdev_t_to_nr(MKDEV(MAJOR_NR,i)));
    - atomic_inc(&bdev->bd_openers); /* avoid invalidate_buffers() */
    - }

    #ifdef CONFIG_BLK_DEV_INITRD
    /* We ought to separate initrd operations here */
    register_disk(NULL, MKDEV(MAJOR_NR,INITRD_MINOR), 1, &fd_fops, rd_size<<1);
    #endif

    + hardsect_size[MAJOR_NR] = rd_hardsec; /* Size of the RAM disk blocks */
    + blksize_size[MAJOR_NR] = rd_blocksizes; /* Avoid set_blocksize() check */
    blk_size[MAJOR_NR] = rd_kbsize; /* Size of the RAM disk in kB */

    /* rd_size is given in kB */
    @@ -468,8 +435,8 @@

    #ifdef MODULE
    module_init(rd_init);
    -#endif
    module_exit(rd_cleanup);
    +#endif

    /* loadable module support */
    MODULE_PARM (rd_size, "1i");

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

    \
     
     \ /
      Last update: 2005-03-22 13:56    [W:0.033 / U:158.184 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site