Skip to content

Commit aa83e53

Browse files
author
Lou
committed
use xfs_repair to check and repair xfs filesystem
Signed-off-by: Lou <[email protected]>
1 parent e2fb8e6 commit aa83e53

File tree

2 files changed

+115
-37
lines changed

2 files changed

+115
-37
lines changed

mount/mount_linux.go

+69-24
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,54 @@ func (mounter *Mounter) GetMountRefs(pathname string) ([]string, error) {
256256
return SearchMountPoints(realpath, procMountInfoPath)
257257
}
258258

259+
// checkAndRepairFileSystem checks and repairs filesystems using command fsck.
260+
func (mounter *SafeFormatAndMount) checkAndRepairFilesystem(source string) error {
261+
klog.V(4).Infof("Checking for issues with fsck on disk: %s", source)
262+
args := []string{"-a", source}
263+
out, err := mounter.Exec.Command("fsck", args...).CombinedOutput()
264+
if err != nil {
265+
ee, isExitError := err.(utilexec.ExitError)
266+
switch {
267+
case err == utilexec.ErrExecutableNotFound:
268+
klog.Warningf("'fsck' not found on system; continuing mount without running 'fsck'.")
269+
case isExitError && ee.ExitStatus() == fsckErrorsCorrected:
270+
klog.Infof("Device %s has errors which were corrected by fsck.", source)
271+
case isExitError && ee.ExitStatus() == fsckErrorsUncorrected:
272+
return NewMountError(HasFilesystemErrors, "'fsck' found errors on device %s but could not correct them: %s", source, string(out))
273+
case isExitError && ee.ExitStatus() > fsckErrorsUncorrected:
274+
klog.Infof("`fsck` error %s", string(out))
275+
}
276+
}
277+
return nil
278+
}
279+
280+
// checkAndRepairXfsFilesystem checks and repairs xfs filesystem using command xfs_repair.
281+
func (mounter *SafeFormatAndMount) checkAndRepairXfsFilesystem(source string) error {
282+
klog.V(4).Infof("Checking for issues with xfs_repair on disk: %s", source)
283+
284+
args := []string{source}
285+
checkArgs := []string{"-n", source}
286+
287+
// check-only using "xfs_repair -n", if the exit status is not 0, perform a "xfs_repair"
288+
_, err := mounter.Exec.Command("xfs_repair", checkArgs...).CombinedOutput()
289+
if err != nil {
290+
if err == utilexec.ErrExecutableNotFound {
291+
klog.Warningf("'xfs_repair' not found on system; continuing mount without running 'xfs_repair'.")
292+
return nil
293+
} else {
294+
klog.Warningf("Filesystem corruption was detected for %s, running xfs_repair to repair", source)
295+
out, err := mounter.Exec.Command("xfs_repair", args...).CombinedOutput()
296+
if err != nil {
297+
return fmt.Errorf("'xfs_repair' found errors on device %s but could not correct them: %s\n", source, out)
298+
} else {
299+
klog.Infof("Device %s has errors which were corrected by xfs_repair.", source)
300+
return nil
301+
}
302+
}
303+
}
304+
return nil
305+
}
306+
259307
// formatAndMount uses unix utils to format and mount the given disk
260308
func (mounter *SafeFormatAndMount) formatAndMount(source string, target string, fstype string, options []string) error {
261309
readOnly := false
@@ -269,26 +317,6 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
269317
options = append(options, "defaults")
270318
var mountErrorValue MountErrorType
271319

272-
if !readOnly {
273-
// Run fsck on the disk to fix repairable issues, only do this for volumes requested as rw.
274-
klog.V(4).Infof("Checking for issues with fsck on disk: %s", source)
275-
args := []string{"-a", source}
276-
out, err := mounter.Exec.Command("fsck", args...).CombinedOutput()
277-
if err != nil {
278-
ee, isExitError := err.(utilexec.ExitError)
279-
switch {
280-
case err == utilexec.ErrExecutableNotFound:
281-
klog.Warningf("'fsck' not found on system; continuing mount without running 'fsck'.")
282-
case isExitError && ee.ExitStatus() == fsckErrorsCorrected:
283-
klog.Infof("Device %s has errors which were corrected by fsck.", source)
284-
case isExitError && ee.ExitStatus() == fsckErrorsUncorrected:
285-
return NewMountError(HasFilesystemErrors, "'fsck' found errors on device %s but could not correct them: %s", source, string(out))
286-
case isExitError && ee.ExitStatus() > fsckErrorsUncorrected:
287-
klog.Infof("`fsck` error %s", string(out))
288-
}
289-
}
290-
}
291-
292320
// Check if the disk is already formatted
293321
existingFormat, err := mounter.GetDiskFormat(source)
294322
if err != nil {
@@ -324,10 +352,27 @@ func (mounter *SafeFormatAndMount) formatAndMount(source string, target string,
324352
}
325353

326354
klog.Infof("Disk successfully formatted (mkfs): %s - %s %s", fstype, source, target)
327-
} else if fstype != existingFormat {
328-
// Verify that the disk is formatted with filesystem type we are expecting
329-
mountErrorValue = FilesystemMismatch
330-
klog.Warningf("Configured to mount disk %s as %s but current format is %s, things might break", source, existingFormat, fstype)
355+
} else {
356+
if fstype != existingFormat {
357+
// Verify that the disk is formatted with filesystem type we are expecting
358+
mountErrorValue = FilesystemMismatch
359+
klog.Warningf("Configured to mount disk %s as %s but current format is %s, things might break", source, existingFormat, fstype)
360+
}
361+
362+
if !readOnly {
363+
// Run check tools on the disk to fix repairable issues, only do this for formatted volumes requested as rw.
364+
var err error
365+
switch existingFormat {
366+
case "xfs":
367+
err = mounter.checkAndRepairXfsFilesystem(source)
368+
default:
369+
err = mounter.checkAndRepairFilesystem(source)
370+
}
371+
372+
if err != nil {
373+
return err
374+
}
375+
}
331376
}
332377

333378
// Mount the disk

mount/safe_format_and_mount_test.go

+46-13
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ func TestSafeFormatAndMount(t *testing.T) {
7979
description: "Test a normal mount of an already formatted device",
8080
fstype: "ext4",
8181
execScripts: []ExecArgs{
82-
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
8382
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "DEVNAME=/dev/foo\nTYPE=ext4\n", nil},
83+
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
8484
},
8585
},
8686
{
@@ -96,7 +96,6 @@ func TestSafeFormatAndMount(t *testing.T) {
9696
description: "Test a normal mount of unformatted device",
9797
fstype: "ext4",
9898
execScripts: []ExecArgs{
99-
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
10099
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 2}},
101100
{"mkfs.ext4", []string{"-F", "-m0", "/dev/foo"}, "", nil},
102101
},
@@ -105,34 +104,34 @@ func TestSafeFormatAndMount(t *testing.T) {
105104
description: "Test 'fsck' fails with exit status 4",
106105
fstype: "ext4",
107106
execScripts: []ExecArgs{
108-
{"fsck", []string{"-a", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 4}},
109107
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "DEVNAME=/dev/foo\nTYPE=ext4\n", nil},
108+
{"fsck", []string{"-a", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 4}},
110109
},
111110
expectedError: fmt.Errorf("'fsck' found errors on device /dev/foo but could not correct them"),
112111
},
113112
{
114113
description: "Test 'fsck' fails with exit status 1 (errors found and corrected)",
115114
fstype: "ext4",
116115
execScripts: []ExecArgs{
117-
{"fsck", []string{"-a", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 1}},
118116
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "DEVNAME=/dev/foo\nTYPE=ext4\n", nil},
117+
{"fsck", []string{"-a", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 1}},
119118
},
120119
},
121120
{
122121
description: "Test 'fsck' fails with exit status other than 1 and 4 (likely unformatted device)",
123122
fstype: "ext4",
124123
execScripts: []ExecArgs{
125-
{"fsck", []string{"-a", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 8}},
126124
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "DEVNAME=/dev/foo\nTYPE=ext4\n", nil},
125+
{"fsck", []string{"-a", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 8}},
127126
},
128127
},
129128
{
130129
description: "Test that 'blkid' is called and fails",
131130
fstype: "ext4",
132131
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
133132
execScripts: []ExecArgs{
134-
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
135133
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "DEVNAME=/dev/foo\nPTTYPE=dos\n", nil},
134+
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
136135
},
137136
expectedError: fmt.Errorf("unknown filesystem type '(null)'"),
138137
},
@@ -141,7 +140,6 @@ func TestSafeFormatAndMount(t *testing.T) {
141140
fstype: "ext4",
142141
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
143142
execScripts: []ExecArgs{
144-
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
145143
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 2}},
146144
{"mkfs.ext4", []string{"-F", "-m0", "/dev/foo"}, "", fmt.Errorf("formatting failed")},
147145
},
@@ -152,7 +150,6 @@ func TestSafeFormatAndMount(t *testing.T) {
152150
fstype: "ext4",
153151
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
154152
execScripts: []ExecArgs{
155-
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
156153
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 2}},
157154
{"mkfs.ext4", []string{"-F", "-m0", "/dev/foo"}, "", nil},
158155
},
@@ -162,7 +159,6 @@ func TestSafeFormatAndMount(t *testing.T) {
162159
description: "Test that 'blkid' is called and confirms unformatted disk, format passes, mount passes",
163160
fstype: "ext4",
164161
execScripts: []ExecArgs{
165-
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
166162
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 2}},
167163
{"mkfs.ext4", []string{"-F", "-m0", "/dev/foo"}, "", nil},
168164
},
@@ -172,7 +168,6 @@ func TestSafeFormatAndMount(t *testing.T) {
172168
description: "Test that 'blkid' is called and confirms unformatted disk, format passes, mount passes with ext3",
173169
fstype: "ext3",
174170
execScripts: []ExecArgs{
175-
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
176171
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 2}},
177172
{"mkfs.ext3", []string{"-F", "-m0", "/dev/foo"}, "", nil},
178173
},
@@ -182,7 +177,6 @@ func TestSafeFormatAndMount(t *testing.T) {
182177
description: "test that none ext4 fs does not get called with ext4 options.",
183178
fstype: "xfs",
184179
execScripts: []ExecArgs{
185-
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
186180
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 2}},
187181
{"mkfs.xfs", []string{"/dev/foo"}, "", nil},
188182
},
@@ -192,21 +186,60 @@ func TestSafeFormatAndMount(t *testing.T) {
192186
description: "Test that 'blkid' is called and reports ext4 partition",
193187
fstype: "ext4",
194188
execScripts: []ExecArgs{
195-
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
196189
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "DEVNAME=/dev/foo\nTYPE=ext4\n", nil},
190+
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
197191
},
198192
},
199193
{
200194
description: "Test that 'blkid' is called but has some usage or other errors (an exit code of 4 is returned)",
201195
fstype: "xfs",
202196
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'"), nil},
203197
execScripts: []ExecArgs{
204-
{"fsck", []string{"-a", "/dev/foo"}, "", nil},
205198
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 4}},
206199
{"mkfs.xfs", []string{"/dev/foo"}, "", nil},
207200
},
208201
expectedError: fmt.Errorf("exit 4"),
209202
},
203+
{
204+
description: "Test that 'xfs_repair' is called only once, no need to repair the filesystem",
205+
fstype: "xfs",
206+
execScripts: []ExecArgs{
207+
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "DEVNAME=/dev/foo\nTYPE=xfs\n", nil},
208+
{"xfs_repair", []string{"-n", "/dev/foo"}, "", nil},
209+
},
210+
expectedError: nil,
211+
},
212+
{
213+
description: "Test that 'xfs_repair' is called twice and repair the filesystem",
214+
fstype: "xfs",
215+
execScripts: []ExecArgs{
216+
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "DEVNAME=/dev/foo\nTYPE=xfs\n", nil},
217+
{"xfs_repair", []string{"-n", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 1}},
218+
{"xfs_repair", []string{"/dev/foo"}, "\ndone\n", nil},
219+
},
220+
expectedError: nil,
221+
},
222+
{
223+
description: "Test that 'xfs_repair' is called twice and repair the filesystem, but mount failed",
224+
fstype: "xfs",
225+
mountErrs: []error{fmt.Errorf("unknown filesystem type '(null)'")},
226+
execScripts: []ExecArgs{
227+
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "DEVNAME=/dev/foo\nTYPE=xfs\n", nil},
228+
{"xfs_repair", []string{"-n", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 1}},
229+
{"xfs_repair", []string{"/dev/foo"}, "\ndone\n", nil},
230+
},
231+
expectedError: fmt.Errorf("unknown filesystem type '(null)'"),
232+
},
233+
{
234+
description: "Test that 'xfs_repair' is called twice but could not repair the filesystem",
235+
fstype: "xfs",
236+
execScripts: []ExecArgs{
237+
{"blkid", []string{"-p", "-s", "TYPE", "-s", "PTTYPE", "-o", "export", "/dev/foo"}, "DEVNAME=/dev/foo\nTYPE=xfs\n", nil},
238+
{"xfs_repair", []string{"-n", "/dev/foo"}, "", &testingexec.FakeExitError{Status: 1}},
239+
{"xfs_repair", []string{"/dev/foo"}, "\nAn error occurred\n", &testingexec.FakeExitError{Status: 1}},
240+
},
241+
expectedError: fmt.Errorf("'xfs_repair' found errors on device %s but could not correct them: %v", "/dev/foo", "\nAn error occurred\n"),
242+
},
210243
}
211244

212245
for _, test := range tests {

0 commit comments

Comments
 (0)