~wb-munzinger/+junk/ocfs2-tools

« back to all changes in this revision

Viewing changes to tunefs.ocfs2/feature_discontig_bg.c

  • Committer: Bazaar Package Importer
  • Author(s): Andres Rodriguez
  • Date: 2011-01-14 12:46:49 UTC
  • mfrom: (1.1.10 upstream) (0.1.10 sid)
  • Revision ID: james.westby@ubuntu.com-20110114124649-vbe5qz211f3zxwuf
Tags: 1.6.3-1ubuntu1
* Merge from debian unstable (LP: #703008).  Remaining changes:
  - Fix configure tests for ld --as-needed.
  - Fix build failure with ld --no-add-needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c; c-basic-offset: 8; -*-
 
2
 * vim: noexpandtab sw=8 ts=8 sts=0:
 
3
 *
 
4
 * feature_discontig_alloc.c
 
5
 *
 
6
 * ocfs2 tune utility for enabling and disabling the discontig_alloc feature.
 
7
 *
 
8
 * Copyright (C) 2010 Oracle.  All rights reserved.
 
9
 *
 
10
 * This program is free software; you can redistribute it and/or
 
11
 * modify it under the terms of the GNU General Public
 
12
 * License version 2 as published by the Free Software Foundation.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
 * General Public License for more details.
 
18
 */
 
19
 
 
20
#include <stdio.h>
 
21
#include <stdlib.h>
 
22
#include <string.h>
 
23
#include <sys/stat.h>
 
24
#include <ctype.h>
 
25
#include <inttypes.h>
 
26
#include <assert.h>
 
27
 
 
28
#include "ocfs2/ocfs2.h"
 
29
 
 
30
#include "libocfs2ne.h"
 
31
 
 
32
static int enable_discontig_bg(ocfs2_filesys *fs, int flags)
 
33
{
 
34
        errcode_t ret = 0;
 
35
        struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super);
 
36
        struct tools_progress *prog;
 
37
 
 
38
        if (ocfs2_supports_discontig_bg(super)) {
 
39
                verbosef(VL_APP,
 
40
                         "Discontiguous block group feature is already enabled;"
 
41
                         " nothing to enable\n");
 
42
                goto out;
 
43
        }
 
44
 
 
45
        if (!tools_interact("Enable the discontiguous block group feature on "
 
46
                            "device \"%s\"? ",
 
47
                            fs->fs_devname))
 
48
                goto out;
 
49
 
 
50
        prog = tools_progress_start("Enable discontig block group",
 
51
                                    "discontig bg", 1);
 
52
        if (!prog) {
 
53
                ret = TUNEFS_ET_NO_MEMORY;
 
54
                tcom_err(ret, "while initializing the progress display");
 
55
                goto out;
 
56
        }
 
57
 
 
58
        OCFS2_SET_INCOMPAT_FEATURE(super, OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG);
 
59
        tunefs_block_signals();
 
60
        ret = ocfs2_write_super(fs);
 
61
        tunefs_unblock_signals();
 
62
        if (ret)
 
63
                tcom_err(ret, "while writing out the superblock");
 
64
 
 
65
        tools_progress_step(prog, 1);
 
66
        tools_progress_stop(prog);
 
67
out:
 
68
        return ret;
 
69
}
 
70
 
 
71
struct discontig_bg {
 
72
        uint64_t bg_blkno;
 
73
        struct discontig_bg *next;
 
74
};
 
75
 
 
76
struct no_discontig_bg_ctxt {
 
77
        ocfs2_filesys *fs;
 
78
        struct tools_progress *prog;
 
79
        char *bg_buf;
 
80
        errcode_t ret;
 
81
        int has_discontig;
 
82
        struct discontig_bg *bg_list;
 
83
};
 
84
 
 
85
/*
 
86
 * Check whether the gd_blkno is a discontig block group, and
 
87
 * if yes set has_discontig and abort.
 
88
 * It also check whether bg_size is a new value, if yes, add
 
89
 * it to the list so that we can change it later.
 
90
 */
 
91
static int check_discontig_bg(ocfs2_filesys *fs, uint64_t gd_blkno,
 
92
                             int chain_num, void *priv_data)
 
93
{
 
94
        struct no_discontig_bg_ctxt *ctxt = priv_data;
 
95
        struct ocfs2_group_desc *gd;
 
96
        struct discontig_bg *bg;
 
97
 
 
98
        ctxt->ret = ocfs2_read_group_desc(fs, gd_blkno, ctxt->bg_buf);
 
99
        if (ctxt->ret) {
 
100
                tcom_err(ctxt->ret, "while reading group descriptor %"PRIu64,
 
101
                         gd_blkno);
 
102
                return OCFS2_CHAIN_ERROR;
 
103
        }
 
104
 
 
105
        gd = (struct ocfs2_group_desc *)ctxt->bg_buf;
 
106
 
 
107
        if (ocfs2_gd_is_discontig(gd)) {
 
108
                ctxt->has_discontig = 1;
 
109
                return OCFS2_CHAIN_ABORT;
 
110
        }
 
111
 
 
112
        if (gd->bg_size == ocfs2_group_bitmap_size(fs->fs_blocksize, 0,
 
113
                        OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat))
 
114
                return 0;
 
115
 
 
116
        /*
 
117
         * OK, now the gd isn't discontiguous while bg_size has
 
118
         * the new size. Record it so that we can change it later.
 
119
         */
 
120
        ctxt->ret = ocfs2_malloc0(sizeof(struct discontig_bg), &bg);
 
121
        if (ctxt->ret) {
 
122
                tcom_err(ctxt->ret, "while allocating discontig_bg");
 
123
                return OCFS2_CHAIN_ABORT;
 
124
        }
 
125
 
 
126
        bg->bg_blkno = gd_blkno;
 
127
        bg->next = ctxt->bg_list;
 
128
        ctxt->bg_list = bg;
 
129
        return 0;
 
130
}
 
131
 
 
132
static errcode_t find_discontig_bg(struct no_discontig_bg_ctxt *ctxt)
 
133
{
 
134
        int i, iret;
 
135
        uint64_t blkno;
 
136
 
 
137
        ctxt->prog = tools_progress_start("Scanning suballocators",
 
138
                                          "scanning", 0);
 
139
        if (!ctxt->prog) {
 
140
                ctxt->ret = TUNEFS_ET_NO_MEMORY;
 
141
                tcom_err(ctxt->ret, "while initializing the progress display");
 
142
                goto out;
 
143
        }
 
144
 
 
145
        /* iterate every inode_alloc first. */
 
146
        for (i = 0; i < OCFS2_RAW_SB(ctxt->fs->fs_super)->s_max_slots; i++) {
 
147
                ctxt->ret = ocfs2_lookup_system_inode(ctxt->fs,
 
148
                                                INODE_ALLOC_SYSTEM_INODE,
 
149
                                                i, &blkno);
 
150
                if (ctxt->ret) {
 
151
                        tcom_err(ctxt->ret, "while finding inode alloc %d", i);
 
152
                        goto out;
 
153
                }
 
154
 
 
155
                iret = ocfs2_chain_iterate(ctxt->fs, blkno,
 
156
                                           check_discontig_bg, ctxt);
 
157
                if (ctxt->ret) {
 
158
                        tcom_err(ctxt->ret, "while iterating inode alloc "
 
159
                                 "%d", i);
 
160
                        goto out;
 
161
                }
 
162
                if (iret == OCFS2_CHAIN_ABORT || iret == OCFS2_CHAIN_ERROR)
 
163
                        goto out;
 
164
                tools_progress_step(ctxt->prog, 1);
 
165
        }
 
166
 
 
167
        /* iterate every extent_alloc now. */
 
168
        for (i = 0; i < OCFS2_RAW_SB(ctxt->fs->fs_super)->s_max_slots; i++) {
 
169
                ctxt->ret = ocfs2_lookup_system_inode(ctxt->fs,
 
170
                                                EXTENT_ALLOC_SYSTEM_INODE,
 
171
                                                i, &blkno);
 
172
                if (ctxt->ret) {
 
173
                        tcom_err(ctxt->ret, "while finding extent alloc %d", i);
 
174
                        goto out;
 
175
                }
 
176
 
 
177
                iret = ocfs2_chain_iterate(ctxt->fs, blkno,
 
178
                                           check_discontig_bg, ctxt);
 
179
                if (ctxt->ret) {
 
180
                        tcom_err(ctxt->ret, "while iterating extent alloc "
 
181
                                 "%d", i);
 
182
                        goto out;
 
183
                }
 
184
                if (iret == OCFS2_CHAIN_ABORT || iret == OCFS2_CHAIN_ERROR)
 
185
                        goto out;
 
186
                tools_progress_step(ctxt->prog, 1);
 
187
        }
 
188
 
 
189
out:
 
190
        if (ctxt->prog) {
 
191
                tools_progress_stop(ctxt->prog);
 
192
                ctxt->prog = NULL;
 
193
        }
 
194
 
 
195
        return ctxt->ret;
 
196
}
 
197
 
 
198
static errcode_t change_bg_size(struct no_discontig_bg_ctxt *ctxt)
 
199
{
 
200
        errcode_t ret = 0;
 
201
        uint64_t bg_blkno;
 
202
        struct discontig_bg *bg;
 
203
        struct ocfs2_group_desc *gd;
 
204
 
 
205
        while (ctxt->bg_list) {
 
206
                bg = ctxt->bg_list;
 
207
                ctxt->bg_list = bg->next;
 
208
                bg_blkno = bg->bg_blkno;
 
209
                ocfs2_free(&bg);
 
210
 
 
211
                ret = ocfs2_read_group_desc(ctxt->fs, bg_blkno, ctxt->bg_buf);
 
212
                if (ret) {
 
213
                        tcom_err(ctxt->ret, "while reading group descriptor "
 
214
                                 "%"PRIu64, bg_blkno);
 
215
                        goto out;
 
216
                }
 
217
 
 
218
                gd = (struct ocfs2_group_desc *)ctxt->bg_buf;
 
219
 
 
220
                gd->bg_size = ocfs2_group_bitmap_size(ctxt->fs->fs_blocksize,
 
221
                                                      0, 0);
 
222
 
 
223
                ret = ocfs2_write_group_desc(ctxt->fs,
 
224
                                             bg_blkno, ctxt->bg_buf);
 
225
                if (ret) {
 
226
                        tcom_err(ctxt->ret, "while writing group descriptor "
 
227
                                 "%"PRIu64, bg->bg_blkno);
 
228
                        goto out;
 
229
                }
 
230
        }
 
231
 
 
232
out:
 
233
        return ret;
 
234
}
 
235
 
 
236
static int disable_discontig_bg(ocfs2_filesys *fs, int flags)
 
237
{
 
238
        errcode_t ret = 0;
 
239
        struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super);
 
240
        struct tools_progress *prog;
 
241
        struct no_discontig_bg_ctxt ctxt;
 
242
        struct discontig_bg *tmp;
 
243
 
 
244
        memset(&ctxt, 0, sizeof(ctxt));
 
245
 
 
246
        if (!ocfs2_supports_discontig_bg(super)) {
 
247
                verbosef(VL_APP,
 
248
                         "Discontiguous block group feature is already "
 
249
                         "disabled; nothing to disable\n");
 
250
                goto out;
 
251
        }
 
252
 
 
253
        if (!tools_interact("Disable the discontiguous block group feature on "
 
254
                            "device \"%s\"? ",
 
255
                            fs->fs_devname))
 
256
                goto out;
 
257
 
 
258
        prog = tools_progress_start("Enable discontig block group",
 
259
                                    "nodiscontig-bg", 4);
 
260
        if (!prog) {
 
261
                ret = TUNEFS_ET_NO_MEMORY;
 
262
                tcom_err(ret, "while initializing the progress display");
 
263
                goto out;
 
264
        }
 
265
 
 
266
        ctxt.fs = fs;
 
267
        ret = ocfs2_malloc_block(fs->fs_io, &ctxt.bg_buf);
 
268
        if (ret) {
 
269
                tcom_err(ret, "while mallocing blocks for group read");
 
270
                goto out;
 
271
        }
 
272
 
 
273
        ret = find_discontig_bg(&ctxt);
 
274
        if (ret) {
 
275
                tcom_err(ret, "while finding discontiguous block group");
 
276
                goto out;
 
277
        }
 
278
 
 
279
        tools_progress_step(prog, 1);
 
280
 
 
281
        if (ctxt.has_discontig) {
 
282
                tcom_err(0, "We can't disable discontig feature while "
 
283
                         "we have some discontiguous block groups");
 
284
                goto out;
 
285
        }
 
286
 
 
287
        ret = change_bg_size(&ctxt);
 
288
        if (ret) {
 
289
                tcom_err(ret, "while changing bg size for block group");
 
290
                goto out;
 
291
        }
 
292
 
 
293
        OCFS2_CLEAR_INCOMPAT_FEATURE(super,
 
294
                                     OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG);
 
295
        tunefs_block_signals();
 
296
        ret = ocfs2_write_super(fs);
 
297
        tunefs_unblock_signals();
 
298
        if (ret)
 
299
                tcom_err(ret, "while writing out the superblock");
 
300
 
 
301
        tools_progress_step(prog, 1);
 
302
out:
 
303
        if (ctxt.bg_buf)
 
304
                ocfs2_free(&ctxt.bg_buf);
 
305
        while (ctxt.bg_list) {
 
306
                tmp = ctxt.bg_list;
 
307
                ctxt.bg_list = tmp->next;
 
308
                ocfs2_free(&tmp);
 
309
        }
 
310
 
 
311
        if (prog)
 
312
                tools_progress_stop(prog);
 
313
        return ret;
 
314
}
 
315
 
 
316
DEFINE_TUNEFS_FEATURE_INCOMPAT(discontig_bg,
 
317
                               OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG,
 
318
                               TUNEFS_FLAG_RW | TUNEFS_FLAG_ALLOCATION |
 
319
                               TUNEFS_FLAG_LARGECACHE,
 
320
                               enable_discontig_bg,
 
321
                               disable_discontig_bg);
 
322
 
 
323
#ifdef DEBUG_EXE
 
324
int main(int argc, char *argv[])
 
325
{
 
326
        return tunefs_feature_main(argc, argv, &discontig_bg_feature);
 
327
}
 
328
#endif