diff options
Diffstat (limited to 'fs/reiserfs/resize.c')
-rw-r--r-- | fs/reiserfs/resize.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c new file mode 100644 index 000000000000..170012078b76 --- /dev/null +++ b/fs/reiserfs/resize.c | |||
@@ -0,0 +1,182 @@ | |||
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 <linux/reiserfs_fs.h> | ||
17 | #include <linux/reiserfs_fs_sb.h> | ||
18 | #include <linux/buffer_head.h> | ||
19 | |||
20 | int reiserfs_resize (struct super_block * s, unsigned long block_count_new) | ||
21 | { | ||
22 | int err = 0; | ||
23 | struct reiserfs_super_block * sb; | ||
24 | struct reiserfs_bitmap_info *bitmap; | ||
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("reiserfs_resize: unable to resize a reiserfs without distributed bitmap (fs version < 3.5.12)\n"); | ||
58 | return -ENOTSUPP; | ||
59 | } | ||
60 | |||
61 | /* count used bits in last bitmap block */ | ||
62 | block_r = SB_BLOCK_COUNT(s) - | ||
63 | (SB_BMAP_NR(s) - 1) * s->s_blocksize * 8; | ||
64 | |||
65 | /* count bitmap blocks in new fs */ | ||
66 | bmap_nr_new = block_count_new / ( s->s_blocksize * 8 ); | ||
67 | block_r_new = block_count_new - bmap_nr_new * s->s_blocksize * 8; | ||
68 | if (block_r_new) | ||
69 | bmap_nr_new++; | ||
70 | else | ||
71 | block_r_new = s->s_blocksize * 8; | ||
72 | |||
73 | /* save old values */ | ||
74 | block_count = SB_BLOCK_COUNT(s); | ||
75 | bmap_nr = SB_BMAP_NR(s); | ||
76 | |||
77 | /* resizing of reiserfs bitmaps (journal and real), if needed */ | ||
78 | if (bmap_nr_new > bmap_nr) { | ||
79 | /* reallocate journal bitmaps */ | ||
80 | if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) { | ||
81 | printk("reiserfs_resize: unable to allocate memory for journal bitmaps\n"); | ||
82 | unlock_super(s) ; | ||
83 | return -ENOMEM ; | ||
84 | } | ||
85 | /* the new journal bitmaps are zero filled, now we copy in the bitmap | ||
86 | ** node pointers from the old journal bitmap structs, and then | ||
87 | ** transfer the new data structures into the journal struct. | ||
88 | ** | ||
89 | ** using the copy_size var below allows this code to work for | ||
90 | ** both shrinking and expanding the FS. | ||
91 | */ | ||
92 | copy_size = bmap_nr_new < bmap_nr ? bmap_nr_new : bmap_nr ; | ||
93 | copy_size = copy_size * sizeof(struct reiserfs_list_bitmap_node *) ; | ||
94 | for (i = 0 ; i < JOURNAL_NUM_BITMAPS ; i++) { | ||
95 | struct reiserfs_bitmap_node **node_tmp ; | ||
96 | jb = SB_JOURNAL(s)->j_list_bitmap + i ; | ||
97 | memcpy(jbitmap[i].bitmaps, jb->bitmaps, copy_size) ; | ||
98 | |||
99 | /* just in case vfree schedules on us, copy the new | ||
100 | ** pointer into the journal struct before freeing the | ||
101 | ** old one | ||
102 | */ | ||
103 | node_tmp = jb->bitmaps ; | ||
104 | jb->bitmaps = jbitmap[i].bitmaps ; | ||
105 | vfree(node_tmp) ; | ||
106 | } | ||
107 | |||
108 | /* allocate additional bitmap blocks, reallocate array of bitmap | ||
109 | * block pointers */ | ||
110 | bitmap = vmalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new); | ||
111 | if (!bitmap) { | ||
112 | /* Journal bitmaps are still supersized, but the memory isn't | ||
113 | * leaked, so I guess it's ok */ | ||
114 | printk("reiserfs_resize: unable to allocate memory.\n"); | ||
115 | return -ENOMEM; | ||
116 | } | ||
117 | memset (bitmap, 0, sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s)); | ||
118 | for (i = 0; i < bmap_nr; i++) | ||
119 | bitmap[i] = old_bitmap[i]; | ||
120 | |||
121 | /* This doesn't go through the journal, but it doesn't have to. | ||
122 | * The changes are still atomic: We're synced up when the journal | ||
123 | * transaction begins, and the new bitmaps don't matter if the | ||
124 | * transaction fails. */ | ||
125 | for (i = bmap_nr; i < bmap_nr_new; i++) { | ||
126 | bitmap[i].bh = sb_getblk(s, i * s->s_blocksize * 8); | ||
127 | memset(bitmap[i].bh->b_data, 0, sb_blocksize(sb)); | ||
128 | reiserfs_test_and_set_le_bit(0, bitmap[i].bh->b_data); | ||
129 | |||
130 | set_buffer_uptodate(bitmap[i].bh); | ||
131 | mark_buffer_dirty(bitmap[i].bh) ; | ||
132 | sync_dirty_buffer(bitmap[i].bh); | ||
133 | // update bitmap_info stuff | ||
134 | bitmap[i].first_zero_hint=1; | ||
135 | bitmap[i].free_count = sb_blocksize(sb) * 8 - 1; | ||
136 | } | ||
137 | /* free old bitmap blocks array */ | ||
138 | SB_AP_BITMAP(s) = bitmap; | ||
139 | vfree (old_bitmap); | ||
140 | } | ||
141 | |||
142 | /* begin transaction, if there was an error, it's fine. Yes, we have | ||
143 | * incorrect bitmaps now, but none of it is ever going to touch the | ||
144 | * disk anyway. */ | ||
145 | err = journal_begin(&th, s, 10); | ||
146 | if (err) | ||
147 | return err; | ||
148 | |||
149 | /* correct last bitmap blocks in old and new disk layout */ | ||
150 | reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1].bh, 1); | ||
151 | for (i = block_r; i < s->s_blocksize * 8; i++) | ||
152 | reiserfs_test_and_clear_le_bit(i, | ||
153 | SB_AP_BITMAP(s)[bmap_nr - 1].bh->b_data); | ||
154 | SB_AP_BITMAP(s)[bmap_nr - 1].free_count += s->s_blocksize * 8 - block_r; | ||
155 | if ( !SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint) | ||
156 | SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint = block_r; | ||
157 | |||
158 | journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr - 1].bh); | ||
159 | |||
160 | reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh, 1); | ||
161 | for (i = block_r_new; i < s->s_blocksize * 8; i++) | ||
162 | reiserfs_test_and_set_le_bit(i, | ||
163 | SB_AP_BITMAP(s)[bmap_nr_new - 1].bh->b_data); | ||
164 | journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh); | ||
165 | |||
166 | SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count -= s->s_blocksize * 8 - block_r_new; | ||
167 | /* Extreme case where last bitmap is the only valid block in itself. */ | ||
168 | if ( !SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count ) | ||
169 | SB_AP_BITMAP(s)[bmap_nr_new - 1].first_zero_hint = 0; | ||
170 | /* update super */ | ||
171 | reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ; | ||
172 | free_blocks = SB_FREE_BLOCKS(s); | ||
173 | PUT_SB_FREE_BLOCKS(s, free_blocks + (block_count_new - block_count - (bmap_nr_new - bmap_nr))); | ||
174 | PUT_SB_BLOCK_COUNT(s, block_count_new); | ||
175 | PUT_SB_BMAP_NR(s, bmap_nr_new); | ||
176 | s->s_dirt = 1; | ||
177 | |||
178 | journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); | ||
179 | |||
180 | SB_JOURNAL(s)->j_must_wait = 1; | ||
181 | return journal_end(&th, s, 10); | ||
182 | } | ||