#!/bin/bash # Please leave 'added_bricks' as empty if you want 100% defrag. # If you want to move data to newly added bricks, properly give # brick info as ":" form (which was given # in 'gluster volume create' command) # More than one brick can be given with space inbetween. # # (c) 2010 Gluster Inc # set -e; # #added_bricks="node1:/gfs/export1" # added_bricks="" CP="cp" MV="mv" scan_dir() { path=$1; # run defrag on files first # find "$path" -maxdepth 1 -type f -perm +01000 -exec $0 '{}' \; for subdir in $(find "$path" -maxdepth 1 -type d | sed 1d); do $0 "$subdir"; done } fix_xattr() { path=$1; getfattr -n trusted.distribute.fix.layout "$path" 2>/dev/null; } rsync_filename() { path=$1 dir=$(dirname "$path"); file=$(basename "$path"); echo "$dir/.$file.zr$$"; } relocate_file() { path=$1; # Make sure we don't 'defrag' valid file. stat_info=$(stat -c '%a' "$path"); if [ $stat_info -lt 1000 ] ; then return; fi size=$(stat -c '%s' "$path"); # If there are some entries in added_bricks, then check # if the link file is present on those nodes, if not, # set flag=1, so full defrag happens flag=0; for bricks in ${added_bricks}; do linknode=$(getfattr --only-values -n trusted.distribute.linkinfo $path 2>/dev/null); if [ -z $linknode ] ; then return; fi current_brick=${linknode:0:${#bricks}}; if [ "${bricks}" == "${current_brick}" ]; then flag=1; fi done if [ -z ${added_bricks} ] ; then flag=1; fi if [ $flag -ne 1 ]; then return; fi tmp_path=$(rsync_filename "$path"); pre_mtime=$(stat -c '%Y' "$path"); $CP -a "$path" "$tmp_path"; post_mtime=$(stat -c '%Y' "$path"); if [ $pre_mtime = $post_mtime ]; then chmod -t "$tmp_path"; $MV "$tmp_path" "$path"; echo "file '$path' relocated" else echo "file '$path' modified during defrag. skipping" rm -f "$tmp_path"; fi } defrag_usage() { echo "Usage: $0 " } main() { path="$1"; if [ -z "$path" ]; then defrag_usage; return; fi if [ -d "$path" ]; then fix_xattr "$path"; scan_dir "$path"; else relocate_file "$@"; fi } main "$1"