linux/fs/reiserfs/resize.c
<<
>>
Prefs
   1/*
   2 * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
   3 */
   4
   5/*
   6 * Written by Alexander Zarochentcev.
   7 *
   8 * The kernel part of the (on-line) reiserfs resizer.
   9 */
  10
  11#include <linux/kernel.h>
  12#include <linux/mm.h>
  13#include <linux/vmalloc.h>
  14#include <linux/string.h>
  15#include <linux/errno.h>
  16#include "reiserfs.h"
  17#include <linux/buffer_head.h>
  18
  19int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
  20{
  21        int err = 0;
  22        struct reiserfs_super_block *sb;
  23        struct reiserfs_bitmap_info *bitmap;
  24        struct reiserfs_bitmap_info *info;
  25        struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s);
  26        struct buffer_head *bh;
  27        struct reiserfs_transaction_handle th;
  28        unsigned int bmap_nr_new, bmap_nr;
  29        unsigned int block_r_new, block_r;
  30
  31        struct reiserfs_list_bitmap *jb;
  32        struct reiserfs_list_bitmap jbitmap[JOURNAL_NUM_BITMAPS];
  33
  34        unsigned long int block_count, free_blocks;
  35        int i;
  36        int copy_size;
  37
  38        sb = SB_DISK_SUPER_BLOCK(s);
  39
  40        if (SB_BLOCK_COUNT(s) >= block_count_new) {
  41                printk("can\'t shrink filesystem on-line\n");
  42                return -EINVAL;
  43        }
  44
  45        /* check the device size */
  46        bh = sb_bread(s, block_count_new - 1);
  47        if (!bh) {
  48                printk("reiserfs_resize: can\'t read last block\n");
  49                return -EINVAL;
  50        }
  51        bforget(bh);
  52
  53        /* old disk layout detection; those partitions can be mounted, but
  54         * cannot be resized */
  55        if (SB_BUFFER_WITH_SB(s)->b_blocknr * SB_BUFFER_WITH_SB(s)->b_size
  56            != REISERFS_DISK_OFFSET_IN_BYTES) {
  57                printk
  58                    ("reiserfs_resize: unable to resize a reiserfs without distributed bitmap (fs version < 3.5.12)\n");
  59                return -ENOTSUPP;
  60        }
  61
  62        /* count used bits in last bitmap block */
  63        block_r = SB_BLOCK_COUNT(s) -
  64                        (reiserfs_bmap_count(s) - 1) * s->s_blocksize * 8;
  65
  66        /* count bitmap blocks in new fs */
  67        bmap_nr_new = block_count_new / (s->s_blocksize * 8);
  68        block_r_new = block_count_new - bmap_nr_new * s->s_blocksize * 8;
  69        if (block_r_new)
  70                bmap_nr_new++;
  71        else
  72                block_r_new = s->s_blocksize * 8;
  73
  74        /* save old values */
  75        block_count = SB_BLOCK_COUNT(s);
  76        bmap_nr = reiserfs_bmap_count(s);
  77
  78        /* resizing of reiserfs bitmaps (journal and real), if needed */
  79        if (bmap_nr_new > bmap_nr) {
  80                /* reallocate journal bitmaps */
  81                if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) {
  82                        printk
  83                            ("reiserfs_resize: unable to allocate memory for journal bitmaps\n");
  84                        return -ENOMEM;
  85                }
  86                /* the new journal bitmaps are zero filled, now we copy in the bitmap
  87                 ** node pointers from the old journal bitmap structs, and then
  88                 ** transfer the new data structures into the journal struct.
  89                 **
  90                 ** using the copy_size var below allows this code to work for
  91                 ** both shrinking and expanding the FS.
  92                 */
  93                copy_size = bmap_nr_new < bmap_nr ? bmap_nr_new : bmap_nr;
  94                copy_size =
  95                    copy_size * sizeof(struct reiserfs_list_bitmap_node *);
  96                for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) {
  97                        struct reiserfs_bitmap_node **node_tmp;
  98                        jb = SB_JOURNAL(s)->j_list_bitmap + i;
  99                        memcpy(jbitmap[i].bitmaps, jb->bitmaps, copy_size);
 100
 101                        /* just in case vfree schedules on us, copy the new
 102                         ** pointer into the journal struct before freeing the
 103                         ** old one
 104                         */
 105                        node_tmp = jb->bitmaps;
 106                        jb->bitmaps = jbitmap[i].bitmaps;
 107                        vfree(node_tmp);
 108                }
 109
 110                /* allocate additional bitmap blocks, reallocate array of bitmap
 111                 * block pointers */
 112                bitmap =
 113                    vzalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
 114                if (!bitmap) {
 115                        /* Journal bitmaps are still supersized, but the memory isn't
 116                         * leaked, so I guess it's ok */
 117                        printk("reiserfs_resize: unable to allocate memory.\n");
 118                        return -ENOMEM;
 119                }
 120                for (i = 0; i < bmap_nr; i++)
 121                        bitmap[i] = old_bitmap[i];
 122
 123                /* This doesn't go through the journal, but it doesn't have to.
 124                 * The changes are still atomic: We're synced up when the journal
 125                 * transaction begins, and the new bitmaps don't matter if the
 126                 * transaction fails. */
 127                for (i = bmap_nr; i < bmap_nr_new; i++) {
 128                        /* don't use read_bitmap_block since it will cache
 129                         * the uninitialized bitmap */
 130                        bh = sb_bread(s, i * s->s_blocksize * 8);
 131                        if (!bh) {
 132                                vfree(bitmap);
 133                                return -EIO;
 134                        }
 135                        memset(bh->b_data, 0, sb_blocksize(sb));
 136                        reiserfs_set_le_bit(0, bh->b_data);
 137                        reiserfs_cache_bitmap_metadata(s, bh, bitmap + i);
 138
 139                        set_buffer_uptodate(bh);
 140                        mark_buffer_dirty(bh);
 141                        reiserfs_write_unlock(s);
 142                        sync_dirty_buffer(bh);
 143                        reiserfs_write_lock(s);
 144                        // update bitmap_info stuff
 145                        bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
 146                        brelse(bh);
 147                }
 148                /* free old bitmap blocks array */
 149                SB_AP_BITMAP(s) = bitmap;
 150                vfree(old_bitmap);
 151        }
 152
 153        /* begin transaction, if there was an error, it's fine. Yes, we have
 154         * incorrect bitmaps now, but none of it is ever going to touch the
 155         * disk anyway. */
 156        err = journal_begin(&th, s, 10);
 157        if (err)
 158                return err;
 159
 160        /* Extend old last bitmap block - new blocks have been made available */
 161        info = SB_AP_BITMAP(s) + bmap_nr - 1;
 162        bh = reiserfs_read_bitmap_block(s, bmap_nr - 1);
 163        if (!bh) {
 164                int jerr = journal_end(&th, s, 10);
 165                if (jerr)
 166                        return jerr;
 167                return -EIO;
 168        }
 169
 170        reiserfs_prepare_for_journal(s, bh, 1);
 171        for (i = block_r; i < s->s_blocksize * 8; i++)
 172                reiserfs_clear_le_bit(i, bh->b_data);
 173        info->free_count += s->s_blocksize * 8 - block_r;
 174
 175        journal_mark_dirty(&th, s, bh);
 176        brelse(bh);
 177
 178        /* Correct new last bitmap block - It may not be full */
 179        info = SB_AP_BITMAP(s) + bmap_nr_new - 1;
 180        bh = reiserfs_read_bitmap_block(s, bmap_nr_new - 1);
 181        if (!bh) {
 182                int jerr = journal_end(&th, s, 10);
 183                if (jerr)
 184                        return jerr;
 185                return -EIO;
 186        }
 187
 188        reiserfs_prepare_for_journal(s, bh, 1);
 189        for (i = block_r_new; i < s->s_blocksize * 8; i++)
 190                reiserfs_set_le_bit(i, bh->b_data);
 191        journal_mark_dirty(&th, s, bh);
 192        brelse(bh);
 193
 194        info->free_count -= s->s_blocksize * 8 - block_r_new;
 195        /* update super */
 196        reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
 197        free_blocks = SB_FREE_BLOCKS(s);
 198        PUT_SB_FREE_BLOCKS(s,
 199                           free_blocks + (block_count_new - block_count -
 200                                          (bmap_nr_new - bmap_nr)));
 201        PUT_SB_BLOCK_COUNT(s, block_count_new);
 202        PUT_SB_BMAP_NR(s, bmap_would_wrap(bmap_nr_new) ? : bmap_nr_new);
 203
 204        journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
 205
 206        SB_JOURNAL(s)->j_must_wait = 1;
 207        return journal_end(&th, s, 10);
 208}
 209
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.