Whamcloud - gitweb
LU-17756 lod: add tunable lod.*.max_stripes_per_mdt
[fs/lustre-release.git] / lustre / scripts / remove_updatelog
1 #!/bin/bash
2
3 # remove_updatelogs: emergency remove MDT updatelog files from server.
4 #
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
7 #
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
13 #
14 # Script required parameter is mount point of server FS mounted locally
15 # it accepts also optional options as described below in usage()
16 #
17 # Steps to cleanup problematic llogs:
18 #
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>
29 #
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
34 #
35 # Script allows to cleanup llogs related to specific MDTs by their indices:
36 # # bash remove_updatelog -m 0,1 /mnt/mdt0
37 #
38 # That can be useful when llog corruption occurred over particular MDT
39 # pair, e.g. lustre-MDT0001-osp-MDT0003 reports llog problems, that means
40 # the problem reported by MDT0003 communicating to MDT0001, so remote MDT0003
41 # llog on MDT0001 is corrupted and the script should be ran on MDT0001 to
42 # remove MDT0003 update llog after MDT0001 local ldiskfs/ZFS mount:
43 # #bash remove_updatelog -m 3 <mdt1_mount_point>
44 #
45
46
47 ECHO=echo
48 PROG=$(basename $0)
49 LLOG_READER=${LLOG_READER:-llog_reader}
50 GZIP=${GZIP:-gzip}
51
52 usage() {
53     cat -- <<USAGE 1>&2
54 usage: remove_updatelog [--dry-run|-n] [--mdt|-m indices] [--help|-h]\n
55                         [--quiet|-q] <localmount>
56         --help|-h            show this usage message
57         --mdt|-m <index,...> delete llogs of selected MDTs only
58         --dry-run|-n         only print the names of files to be removed
59         --quiet|-q           run quietly (don't print filenames or status)
60         --zip|-z <name_prefix>
61                         save all llogs into compressed tar archive with given
62                         name prefix using gzip by default. Other compression
63                         tools can be used via GZIP env variable.
64
65 The 'localmount' argument should be an ldiskfs mounted MDT device mountpoint.
66
67 Examples:
68       remove_updatelog /mnt/mdt0
69       remove_updatelog --dry-run /mnt/mdt0
70       remove_updatelog -z /tmp/llogs /mnt/mdt0
71       remove_updatelog -m 0,1 /mnt/mdt0
72 USAGE
73     exit 1
74 }
75
76 OPT_DRYRUN=false
77 OPT_ARCH=""
78 OPT_MOUNT=""
79 OPT_MDTS=()
80 OPT_MDTIDX=()
81
82 # Examine any long options and arguments
83 while [ -n "$*" ]; do
84         arg="$1"
85         case "$arg" in
86         -h|--help) usage;;
87         -m|--mdt) OPT_MDTIDX=($(echo $2 | tr "," " "));;
88         -n|--dry-run) OPT_DRYRUN=true;;
89         -q|--quiet) ECHO=:;;
90         -z|--zip) OPT_ARCH="$2.tar"; shift;;
91         *)
92            [ -d "$arg" ] && OPT_MOUNT="$arg";;
93         esac
94         shift
95 done
96
97 remove_updatelog() {
98         local mntpoint=$OPT_MOUNT
99         local catlist=${mntpoint}/update_log
100         local dir=${mntpoint}/update_log_dir
101         local arch=$OPT_ARCH
102         local length=0
103
104 #       if [[ -z $(df -t ldiskfs $mntpoint 2>/dev/null) ]] ; then
105 #               echo "$PROG: '$mntpoint' is not ldiskfs mount."
106 #               exit 1
107 #       fi
108
109         if $OPT_DRYRUN; then
110                 $ECHO "Dry run was requested, no changes will be applied"
111         fi
112
113         $ECHO "Scan update_log at '$mntpoint':"
114         if [[ ! -f $catlist ]] ; then
115                 echo "$PROG: $catlist doesn't exist already."
116         else
117                 read -r -d '' -a OPT_MDTS <<< $(hexdump -v -e '2/8 " %16x" 2/8 "\n"' $catlist |
118                                                 awk '{print "[0x"$2":0x"$1":0x0]"}')
119
120                 if [[ ! $(which $LLOG_READER 2>/dev/null) ]] ; then
121                         echo "$PROG: $LLOG_READER is missing."
122                         exit 1
123                 fi
124                 [[ -z $arch ]] || tar -cf $arch $catlist 2>/dev/null
125
126                 length=${#OPT_MDTS[@]}
127                 (( ${#OPT_MDTIDX[@]} > 0 )) || OPT_MDTIDX=($(seq 0 $((length - 1))))
128                 echo "Selected MDTS: ${OPT_MDTIDX[*]}"
129                 for i in ${OPT_MDTIDX[@]} ; do
130                         local catalog=$dir/${OPT_MDTS[$i]}
131
132                         if (( $i >= $length)) ; then
133                                 echo "skip wrong index $i, total $length MDTs"
134                                 continue
135                         fi
136
137                         $ECHO "Processing MDT$i llog catalog ${OPT_MDTS[$i]} ..."
138                         if [[ ! -f $catalog ]] ; then
139                                 echo "$PROG: $catalog doesn't exist already."
140                                 continue
141                         fi
142                         [[ -z $arch ]] || tar -rf $arch $catalog 2>/dev/null
143                         if (( $(stat -c %s $catalog) >= 8192 )) ; then
144                                 while read -r plain ; do
145                                         local path
146
147                                         # compatibility checks:
148                                         # old llog reader reports path in /O
149                                         # but correct path in update_log_dir
150                                         if [ ${plain:0:1} == 'O' ] ; then
151                                                 local fid=${plain#"O/"*}
152
153                                                 # old format: O/8589935617/d3/3
154                                                 # get sequence and oid in hex:
155                                                 fid=$(printf "[0x%x:0x%x:0x0]" ${fid%%/*} ${fid##*/})
156                                                 path="$dir/$fid"
157                                         else
158                                                 path=$mntpoint/$plain
159                                         fi
160                                         [[ -z $arch ]] ||
161                                                 tar -rf $arch $path 2>/dev/null
162                                         $ECHO "rm -f $path"
163                                         $OPT_DRYRUN || rm -f $path
164                                 done < <(llog_reader $catalog |
165                                          awk -F "path=" '/path=/ { print $2 }')
166                         else
167                                 echo "$PROG: $catalog is too small."
168                         fi
169                         $ECHO "> $catalog"
170                         $OPT_DRYRUN || > $catalog
171                 done
172         fi
173         if [[ "$arch" ]] ; then
174                 $GZIP -3 $arch
175                 $ECHO "llog archive was created by $GZIP"
176         fi
177 }
178
179 if [ -z $OPT_MOUNT ] ; then
180         echo "Mount is not specified, exiting"
181         exit 1
182 fi
183 remove_updatelog
184
185