3 # remove_updatelogs: emergency remove MDT updatelog files from server.
5 # This is emergency tool to cleanup updatelogs in server if llog records
6 # cannot be removed by regular means, e.g. due to llog corruptions
8 # Tool goes the following:
9 # - goes through update_log catlist to find per-MDT update llog catalog
10 # - process llog catalog to delete all plain llogs in it
11 # - truncate or remove related llog catalog after all
12 # - truncates update_llogs itself if all catalogs were removed
14 # Script required parameter is mount point of server FS mounted locally
15 # it accepts also optional options as described below in usage()
17 # Steps to cleanup problematic llogs:
19 # 1. mount MDT filesystem locally on server as ldiskfs mount
20 # 2. run script first in dry-run mode to make sure it parses llogs as needed:
21 # # bash remove_updatelog -n <ldiskfs_mount>
22 # 3. save all llogs for analysis:
23 # # bash remove_updatelog -n -z /tmp/llogs_saved <ldiskfs_mount>
24 # 4. check that /tmp/llogs_saved.tar.gz exists and has all llogs inside:
25 # # ls -ali /tmp/llogs_saved.tar.gz
26 # # tar -tf /tmp/llog_saved.tar.gz
27 # 5. finally run script to delete all llogs:
28 # # bash remove_updatelog <ldiskfs_mount>
30 # For better llogs compression xz can be used as well, pass it to the script
31 # via GZIP env variable:
32 # # GZIP=xz bash remove_updatelog -n -z /tmp/llogs_saved <ldiskfs_mount>
33 # Archive name will ends with .xz in that case instead of .gz
37 LLOG_READER=${LLOG_READER:-llog_reader}
42 usage: remove_updatelog [--dry-run|-n] [--help|-h] [--quiet|-q] <localmount>
43 --help|-h show this usage message
44 --dry-run|-n only print the names of files to be removed
45 --quiet|-q run quietly (don't print filenames or status)
46 --zip|-z <name_prefix>
47 save all llogs into compressed tar archive with given
48 name prefix using gzip by default. Other compression
49 tools can be used via GZIP env variable.
51 The 'localmount' argument should be an ldiskfs mounted MDT device mountpoint.
54 remove_updatelog /mnt/mdt0
55 remove_updatelog --dry-run /mnt/mdt0
56 remove_changelog -z /tmp/llogs /mnt/mdt0
66 # Examine any long options and arguments
71 -n|--dry-run) OPT_DRYRUN=true;;
73 -z|--zip) OPT_ARCH="$2.tar"; shift;;
75 [ -e "$arg" ] && OPT_MOUNT="$arg" && break
81 local mntpoint=$OPT_MOUNT
82 local catlist=${mntpoint}/update_log
83 local dir=${mntpoint}/update_log_dir
87 if [[ -z $(df -t ldiskfs $mntpoint 2>/dev/null) ]] ; then
88 echo "$PROG: '$mntpoint' is not ldiskfs mount."
93 $ECHO "Dry run was requested, no changes will be applied"
96 $ECHO "Scan update_log at '$mntpoint':"
97 if [[ ! -f $catlist ]] ; then
98 echo "$PROG: $catlist doesn't exist already."
100 read -r -d '' -a OPT_MDTS < <(hexdump -v -e '2/8 " %16x" 2/8 "\n"' $catlist |
101 awk '{print "[0x"$2":0x"$1":0x0]"}')
103 if [[ ! $(which $LLOG_READER 2>/dev/null) ]] ; then
104 echo "$PROG: $LLOG_READER is missing."
107 [[ -z $arch ]] || tar -cf $arch $catlist 2>/dev/null
108 length=${#OPT_MDTS[@]}
109 for (( i = 0; i < ${length}; i++ )); do
110 local catalog=$dir/${OPT_MDTS[$i]}
112 $ECHO "Processing MDT$i llogs ..."
113 if [[ ! -f $catalog ]] ; then
114 echo "$PROG: $catalog doesn't exist already."
117 [[ -z $arch ]] || tar -rf $arch $catalog 2>/dev/null
118 if (( $(stat -c %s $catalog) >= 8192 )) ; then
119 while read -r plain ; do
122 # compatibility checks:
123 # old llog reader reports path in /O
124 # but correct path in update_log_dir
125 if [ ${plain:0:1} == 'O' ] ; then
126 local fid=${plain#"O/"*}
128 # old format: O/8589935617/d3/3
129 # get sequence and oid in hex:
130 fid=$(printf "[0x%x:0x%x:0x0]" ${fid%%/*} ${fid##*/})
133 path=$mntpoint/$plain
136 tar -rf $arch $path 2>/dev/null
138 $OPT_DRYRUN || rm -f $path
139 done < <(llog_reader $catalog |
140 awk -F "path=" '/path=/ { print $2 }')
142 echo "$PROG: $catalog is too small."
145 $OPT_DRYRUN || > $catalog
148 if [[ "$arch" ]] ; then
150 $ECHO "llog archive was created by $GZIP"
154 if [ -z $OPT_MOUNT ] ; then
155 echo "Mount is not specified, exiting"