1
/* -*- mode: c; c-basic-offset: 8; -*-
2
* vim: noexpandtab sw=8 ts=8 sts=0:
4
* feature_discontig_alloc.c
6
* ocfs2 tune utility for enabling and disabling the discontig_alloc feature.
8
* Copyright (C) 2010 Oracle. All rights reserved.
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.
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.
28
#include "ocfs2/ocfs2.h"
30
#include "libocfs2ne.h"
32
static int enable_discontig_bg(ocfs2_filesys *fs, int flags)
35
struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super);
36
struct tools_progress *prog;
38
if (ocfs2_supports_discontig_bg(super)) {
40
"Discontiguous block group feature is already enabled;"
41
" nothing to enable\n");
45
if (!tools_interact("Enable the discontiguous block group feature on "
50
prog = tools_progress_start("Enable discontig block group",
53
ret = TUNEFS_ET_NO_MEMORY;
54
tcom_err(ret, "while initializing the progress display");
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();
63
tcom_err(ret, "while writing out the superblock");
65
tools_progress_step(prog, 1);
66
tools_progress_stop(prog);
73
struct discontig_bg *next;
76
struct no_discontig_bg_ctxt {
78
struct tools_progress *prog;
82
struct discontig_bg *bg_list;
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.
91
static int check_discontig_bg(ocfs2_filesys *fs, uint64_t gd_blkno,
92
int chain_num, void *priv_data)
94
struct no_discontig_bg_ctxt *ctxt = priv_data;
95
struct ocfs2_group_desc *gd;
96
struct discontig_bg *bg;
98
ctxt->ret = ocfs2_read_group_desc(fs, gd_blkno, ctxt->bg_buf);
100
tcom_err(ctxt->ret, "while reading group descriptor %"PRIu64,
102
return OCFS2_CHAIN_ERROR;
105
gd = (struct ocfs2_group_desc *)ctxt->bg_buf;
107
if (ocfs2_gd_is_discontig(gd)) {
108
ctxt->has_discontig = 1;
109
return OCFS2_CHAIN_ABORT;
112
if (gd->bg_size == ocfs2_group_bitmap_size(fs->fs_blocksize, 0,
113
OCFS2_RAW_SB(fs->fs_super)->s_feature_incompat))
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.
120
ctxt->ret = ocfs2_malloc0(sizeof(struct discontig_bg), &bg);
122
tcom_err(ctxt->ret, "while allocating discontig_bg");
123
return OCFS2_CHAIN_ABORT;
126
bg->bg_blkno = gd_blkno;
127
bg->next = ctxt->bg_list;
132
static errcode_t find_discontig_bg(struct no_discontig_bg_ctxt *ctxt)
137
ctxt->prog = tools_progress_start("Scanning suballocators",
140
ctxt->ret = TUNEFS_ET_NO_MEMORY;
141
tcom_err(ctxt->ret, "while initializing the progress display");
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,
151
tcom_err(ctxt->ret, "while finding inode alloc %d", i);
155
iret = ocfs2_chain_iterate(ctxt->fs, blkno,
156
check_discontig_bg, ctxt);
158
tcom_err(ctxt->ret, "while iterating inode alloc "
162
if (iret == OCFS2_CHAIN_ABORT || iret == OCFS2_CHAIN_ERROR)
164
tools_progress_step(ctxt->prog, 1);
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,
173
tcom_err(ctxt->ret, "while finding extent alloc %d", i);
177
iret = ocfs2_chain_iterate(ctxt->fs, blkno,
178
check_discontig_bg, ctxt);
180
tcom_err(ctxt->ret, "while iterating extent alloc "
184
if (iret == OCFS2_CHAIN_ABORT || iret == OCFS2_CHAIN_ERROR)
186
tools_progress_step(ctxt->prog, 1);
191
tools_progress_stop(ctxt->prog);
198
static errcode_t change_bg_size(struct no_discontig_bg_ctxt *ctxt)
202
struct discontig_bg *bg;
203
struct ocfs2_group_desc *gd;
205
while (ctxt->bg_list) {
207
ctxt->bg_list = bg->next;
208
bg_blkno = bg->bg_blkno;
211
ret = ocfs2_read_group_desc(ctxt->fs, bg_blkno, ctxt->bg_buf);
213
tcom_err(ctxt->ret, "while reading group descriptor "
214
"%"PRIu64, bg_blkno);
218
gd = (struct ocfs2_group_desc *)ctxt->bg_buf;
220
gd->bg_size = ocfs2_group_bitmap_size(ctxt->fs->fs_blocksize,
223
ret = ocfs2_write_group_desc(ctxt->fs,
224
bg_blkno, ctxt->bg_buf);
226
tcom_err(ctxt->ret, "while writing group descriptor "
227
"%"PRIu64, bg->bg_blkno);
236
static int disable_discontig_bg(ocfs2_filesys *fs, int flags)
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;
244
memset(&ctxt, 0, sizeof(ctxt));
246
if (!ocfs2_supports_discontig_bg(super)) {
248
"Discontiguous block group feature is already "
249
"disabled; nothing to disable\n");
253
if (!tools_interact("Disable the discontiguous block group feature on "
258
prog = tools_progress_start("Enable discontig block group",
259
"nodiscontig-bg", 4);
261
ret = TUNEFS_ET_NO_MEMORY;
262
tcom_err(ret, "while initializing the progress display");
267
ret = ocfs2_malloc_block(fs->fs_io, &ctxt.bg_buf);
269
tcom_err(ret, "while mallocing blocks for group read");
273
ret = find_discontig_bg(&ctxt);
275
tcom_err(ret, "while finding discontiguous block group");
279
tools_progress_step(prog, 1);
281
if (ctxt.has_discontig) {
282
tcom_err(0, "We can't disable discontig feature while "
283
"we have some discontiguous block groups");
287
ret = change_bg_size(&ctxt);
289
tcom_err(ret, "while changing bg size for block group");
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();
299
tcom_err(ret, "while writing out the superblock");
301
tools_progress_step(prog, 1);
304
ocfs2_free(&ctxt.bg_buf);
305
while (ctxt.bg_list) {
307
ctxt.bg_list = tmp->next;
312
tools_progress_stop(prog);
316
DEFINE_TUNEFS_FEATURE_INCOMPAT(discontig_bg,
317
OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG,
318
TUNEFS_FLAG_RW | TUNEFS_FLAG_ALLOCATION |
319
TUNEFS_FLAG_LARGECACHE,
321
disable_discontig_bg);
324
int main(int argc, char *argv[])
326
return tunefs_feature_main(argc, argv, &discontig_bg_feature);