From 3dbc4484c3275511562f31a6ae6cf507ddbb04ae Mon Sep 17 00:00:00 2001 From: Coly Li Date: Fri, 5 Mar 2010 16:19:20 +0800 Subject: [PATCH 10/15] dx_dirs: add disable indexed-dirs support in tunefs.ocfs2 This patch truncates all directories' indexed tree if '--fs-features noindexed-tree' option is given. The indexed dirs related flags on directory inodes and superblock are cleared too. Signed-off-by: Coly Li Acked-by: Mark Fasheh --- tunefs.ocfs2/feature_indexed_dirs.c | 192 ++++++++++++++++++++++++++++++++++- tunefs.ocfs2/o2ne_err.et | 9 ++ 2 files changed, 199 insertions(+), 2 deletions(-) diff --git a/tunefs.ocfs2/feature_indexed_dirs.c b/tunefs.ocfs2/feature_indexed_dirs.c index 368eb87..e9f87fb 100644 --- a/tunefs.ocfs2/feature_indexed_dirs.c +++ b/tunefs.ocfs2/feature_indexed_dirs.c @@ -6,7 +6,7 @@ * ocfs2 tune utility for enabling and disabling the directory indexing * feature. * - * Copyright (C) 2009 Novell. All rights reserved. + * Copyright (C) 2009, 2010 Novell. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public @@ -30,6 +30,17 @@ #include "libocfs2ne.h" +struct dx_dirs_inode { + struct list_head list; + uint64_t ino; +}; + +struct dx_dirs_context { + errcode_t ret; + uint64_t dx_dirs_nr; + struct list_head inodes; + struct tools_progress *prog; +}; static int enable_indexed_dirs(ocfs2_filesys *fs, int flags) { @@ -71,6 +82,183 @@ out: return ret; } +static errcode_t dx_dir_iterate(ocfs2_filesys *fs, struct ocfs2_dinode *di, + void *user_data) +{ + errcode_t ret = 0; + struct dx_dirs_inode *dx_di = NULL; + struct dx_dirs_context *ctxt= (struct dx_dirs_context *)user_data; + + if (!S_ISDIR(di->i_mode)) + goto bail; + + if (!(di->i_dyn_features & OCFS2_INDEXED_DIR_FL)) + goto bail; + + ret = ocfs2_malloc0(sizeof(struct dx_dirs_inode), &dx_di); + if (ret) { + ret = TUNEFS_ET_NO_MEMORY; + goto bail; + } + + dx_di->ino = di->i_blkno; + ctxt->dx_dirs_nr ++; + list_add_tail(&dx_di->list, &ctxt->inodes); + + tools_progress_step(ctxt->prog, 1); + +bail: + return ret; +} + + +static errcode_t find_indexed_dirs(ocfs2_filesys *fs, + struct dx_dirs_context *ctxt) +{ + errcode_t ret; + + ctxt->prog = tools_progress_start("Scanning filesystem", "scanning", 0); + if (!ctxt->prog) { + ret = TUNEFS_ET_NO_MEMORY; + goto bail; + } + + ret = tunefs_foreach_inode(fs, dx_dir_iterate, ctxt); + if (ret) { + if (ret != TUNEFS_ET_NO_MEMORY) + ret = TUNEFS_ET_DX_DIRS_SCAN_FAILED; + goto bail; + } + + verbosef(VL_APP, + "We have %lu indexed %s to truncate.\n", + ctxt->dx_dirs_nr, + (ctxt->dx_dirs_nr > 1)?"directories":"directory"); + +bail: + if (ctxt->prog) + tools_progress_stop(ctxt->prog); + + return ret; +} + +static errcode_t clean_indexed_dirs(ocfs2_filesys *fs, + struct dx_dirs_context *ctxt) +{ + errcode_t ret = 0; + struct list_head *pos; + struct dx_dirs_inode *dx_di; + struct tools_progress *prog; + uint64_t dirs_truncated = 0; + + prog = tools_progress_start("Truncating indexed dirs", "truncating", + ctxt->dx_dirs_nr); + if (!prog) { + ret = TUNEFS_ET_NO_MEMORY; + goto bail; + } + + list_for_each(pos, &ctxt->inodes) { + dx_di = list_entry(pos, struct dx_dirs_inode, list); + + ret = ocfs2_dx_dir_truncate(fs, dx_di->ino); + if (ret) { + verbosef(VL_APP, + "Truncate directory (ino \"%lu\") failed.", + dx_di->ino); + ret = TUNEFS_ET_DX_DIRS_TRUNCATE_FAILED; + goto bail; + } + dirs_truncated ++; + tools_progress_step(prog, 1); + } + +bail: + tools_progress_stop(prog); + verbosef(VL_APP, + "\"%lu\" from \"%lu\" indexed %s truncated.", + dirs_truncated, ctxt->dx_dirs_nr, + (dirs_truncated <= 1) ? "directory is" : "directories are"); + + return ret; +} + +static void release_dx_dirs_context(struct dx_dirs_context *ctxt) +{ + struct list_head *pos, *n; + struct dx_dirs_inode *dx_di; + + list_for_each_safe(pos, n, &ctxt->inodes) { + dx_di = list_entry(pos, struct dx_dirs_inode, list); + list_del(&dx_di->list); + ocfs2_free(&dx_di); + } +} + +static int disable_indexed_dirs(ocfs2_filesys *fs, int flags) +{ + errcode_t ret = 0; + struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super); + struct dx_dirs_context ctxt; + struct tools_progress *prog = NULL; + + if (!ocfs2_supports_indexed_dirs(super)) { + verbosef(VL_APP, + "Directory indexing feature is not enabled; " + "nothing to disable\n"); + goto out; + } + + if (!tools_interact("Disabling the directory indexing feature on " + "device \"%s\"? ", + fs->fs_devname)) + goto out; + + prog = tools_progress_start("Disable directory indexing", "no dir idx", 2); + if (!prog) { + ret = TUNEFS_ET_NO_MEMORY; + tcom_err(ret, "while initializing the progress display"); + goto out; + } + + memset(&ctxt, 0, sizeof (struct dx_dirs_context)); + INIT_LIST_HEAD(&ctxt.inodes); + ret = find_indexed_dirs(fs, &ctxt); + if (ret) { + tcom_err(ret, "while scanning indexed directories"); + goto out_cleanup; + } + + tools_progress_step(prog, 1); + + tunefs_block_signals(); + ret = clean_indexed_dirs(fs, &ctxt); + if (ret) { + tcom_err(ret, "while truncate indexed directories"); + } + + /* We already touched file system, must disable dx dirs flag here. + * fsck.ocfs2 will handle the orphan indexed trees. */ + OCFS2_CLEAR_INCOMPAT_FEATURE(super, + OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS); + ret = ocfs2_write_super(fs); + tunefs_unblock_signals(); + + if (ret) { + ret = TUNEFS_ET_IO_WRITE_FAILED; + tcom_err(ret, "while writing super block"); + } + + tools_progress_step(prog, 1); +out_cleanup: + release_dx_dirs_context(&ctxt); +out: + if (prog) + tools_progress_stop(prog); + + return ret; +} + /* * TUNEFS_FLAG_ALLOCATION because disabling will want to dealloc * blocks. @@ -79,7 +267,7 @@ DEFINE_TUNEFS_FEATURE_INCOMPAT(indexed_dirs, OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS, TUNEFS_FLAG_RW | TUNEFS_FLAG_ALLOCATION, enable_indexed_dirs, - NULL); + disable_indexed_dirs); #ifdef DEBUG_EXE int main(int argc, char *argv[]) diff --git a/tunefs.ocfs2/o2ne_err.et b/tunefs.ocfs2/o2ne_err.et index 20031a5..c2f700b 100644 --- a/tunefs.ocfs2/o2ne_err.et +++ b/tunefs.ocfs2/o2ne_err.et @@ -85,4 +85,13 @@ ec TUNEFS_ET_ONLINE_NOT_SUPPORTED, ec TUNEFS_ET_CLUSTER_SKIPPED, "Cluster stack initialization was skipped" +ec TUNEFS_ET_DX_DIRS_SCAN_FAILED, + "Scanning inodes for directory indexing failed" + +ec TUNEFS_ET_IO_WRITE_FAILED, + "Write I/O failed" + +ec TUNEFS_ET_DX_DIRS_TRUNCATE_FAILED, + "Truncate directory indexed tree failed" + end -- 1.6.4.2