Bug 1833141

Summary: gfs2_jadd doesn't clean up if it runs out of space
Product: Red Hat Enterprise Linux 8 Reporter: Nate Straz <nstraz>
Component: gfs2-utilsAssignee: Abhijith Das <adas>
Status: CLOSED ERRATA QA Contact: cluster-qe <cluster-qe>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 8.3CC: adas, cluster-maint, gfs2-maint, rhandlin
Target Milestone: rcFlags: pm-rhel: mirror+
Target Release: 8.0   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: gfs2-utils-3.2.0-9.el8 Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of:
: 1834456 1837640 (view as bug list) Environment:
Last Closed: 2020-11-04 02:01:07 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 1834456, 1837640    
Attachments:
Description Flags
gfs2_jadd-out-of-space-issues-and-other-fixes
none
Revised patch - moved error handling fixes to another patch
none
First bash at error handling fixes
none
Revised error handling cleanup patch none

Description Nate Straz 2020-05-07 21:31:02 UTC
Description of problem:

If we run out of space on the file system while gfs2_jadd is trying to create new journals, it exits, leaving files behind and gfs2meta mounted.


Version-Release number of selected component (if applicable):
gfs2-utils-3.2.0-7.el8.x86_64

How reproducible:
easily

Steps to Reproduce:
1. gfs2_jadd too many large journals on a small file system
2.
3.

Actual results:
[root@host-028 ~]# lvcreate -L 1g -n brawl0 brawl
WARNING: gfs2 signature detected on /dev/brawl/brawl0 at offset 65536. Wipe it? [y/n]: y
  Wiping gfs2 signature on /dev/brawl/brawl0.
  Logical volume "brawl0" created.
[root@host-028 ~]# mkfs.gfs2 -p lock_nolock -j 1 -J 128 -O /dev/brawl/brawl0
/dev/brawl/brawl0 is a symbolic link to /dev/dm-2
This will destroy any data on /dev/dm-2
Discarding device contents (may take a while on large devices): Done
Adding journals: Done
Building resource groups: Done
Creating quota file: Done
Writing superblock and syncing: Done
Device:                    /dev/brawl/brawl0
Block size:                4096
Device size:               1.00 GB (262144 blocks)
Filesystem size:           1.00 GB (262142 blocks)
Journals:                  1
Journal size:              128MB
Resource groups:           5
Locking protocol:          "lock_nolock"
Lock table:                ""
UUID:                      914a1553-6647-4df2-8721-3ffc30f56d20
[root@host-028 ~]# mount /dev/brawl/brawl0 /mnt/brawl
[root@host-028 ~]# df /mnt/brawl
Filesystem               1K-blocks   Used Available Use% Mounted on
/dev/mapper/brawl-brawl0   1048400 132404    915996  13% /mnt/brawl
[root@host-028 ~]# gfs2_jadd -j 10 -J 128 /mnt/brawl
add_j: No space left on device
[root@host-028 ~]# df
Filesystem                      1K-blocks    Used Available Use% Mounted on
devtmpfs                           965440       0    965440   0% /dev
tmpfs                              982048   51696    930352   6% /dev/shm
tmpfs                              982048   16892    965156   2% /run
tmpfs                              982048       0    982048   0% /sys/fs/cgroup
/dev/mapper/rhel_host--028-root   6486016 4849696   1636320  75% /
/dev/vda1                         1038336  320660    717676  31% /boot
tmpfs                              196352       0    196352   0% /run/user/0
/dev/mapper/brawl-brawl0          1048400 1048272       128 100% /mnt/brawl
[root@host-028 ~]# mount
...
/dev/mapper/brawl-brawl0 on /mnt/brawl type gfs2 (rw,relatime,seclabel,localflocks)
/mnt/brawl on /tmp/.gfs2meta.eSuC5g type gfs2 (rw,relatime,seclabel,meta,localflocks)
[root@host-028 ~]# ls /tmp/.gfs2meta.eSuC5g/ -l
total 120516
-rw-------. 1 root root         8 May  7 16:17 inum
drwx------. 2 root root      3864 May  7 16:19 jindex
-rw-------. 1 root root 123129856 May  7 16:19 new_inode
drwx------. 2 root root      3864 May  7 16:19 per_node
-rw-------. 1 root root       176 May  7 16:17 quota
-rw-------. 1 root root       480 May  7 16:17 rindex
-rw-------. 1 root root        24 May  7 16:17 statfs
[root@host-028 ~]# ls /tmp/.gfs2meta.eSuC5g/jindex -l
total 919376
-rw-------. 1 root root 134217728 May  7 16:17 journal0
-rw-------. 1 root root 134217728 May  7 16:18 journal1
-rw-------. 1 root root 134217728 May  7 16:18 journal2
-rw-------. 1 root root 134217728 May  7 16:19 journal3
-rw-------. 1 root root 134217728 May  7 16:19 journal4
-rw-------. 1 root root 134217728 May  7 16:19 journal5
-rw-------. 1 root root 134217728 May  7 16:19 journal6


Expected results:
gfs2_jadd should umount gfs2meta and clean up any journals it was not able to completely create (or not make them to begin with)

Additional info:

Comment 1 Nate Straz 2020-05-07 21:32:06 UTC
fsck.gfs2 can not fix these file systems either.

[root@host-028 ~]# fsck.gfs2 -y /dev/brawl/brawl0
Initializing fsck
Validating resource group index.
Level 1 resource group check: Checking if all rgrp and rindex values are good.
(level 1 passed)
File system journal "journal7" is missing or corrupt: pass1 will try to recreate it.

Journal recovery complete.
Starting pass1
Invalid or missing journal7 system inode (is 'free', should be 'inode').
Rebuilding system file "journal7"
get_file_buf
[root@host-028 ~]# echo $?
1

Comment 2 Abhijith Das 2020-05-11 03:20:17 UTC
Created attachment 1687127 [details]
gfs2_jadd-out-of-space-issues-and-other-fixes

If gfs2_jadd runs out of disk space while adding journals, it does
not exit gracefully. It partially does its job and bails out when
it hits -ENOSPC. This leaves the metafs mounted and most likely a
corrupted filesystem that even fsck.gfs2 can't fix.

This patch adds a pre-check that ensures that the journals requested
will fit in the available space before proceeding. Note that this is
not foolproof because gfs2_jadd operates on a mounted filesystem.
While it is required that the filesystem be idle (and mounted on only
one node) while gfs2_jadd is being run, there is nothing stopping a
user from having some I/O process competing with gfs2_jadd for disk
blocks and consequently crashing it.

This patch also does some cleanup of data structures when gfs2_jadd
exits due to errors.

Comment 3 Abhijith Das 2020-05-11 03:33:04 UTC
https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=28472231

Here's a scratch build with the above patch.

Comment 4 Andrew Price 2020-05-11 11:17:35 UTC
(In reply to Abhijith Das from comment #2)
> Created attachment 1687127 [details]
> gfs2_jadd-out-of-space-issues-and-other-fixes

> Note that this is
> not foolproof because gfs2_jadd operates on a mounted filesystem.

I think it would be better to add error handling to the write() and close() calls, as currently write() errors cause an exit() without cleanup, and the close()es aren't checked at all. It probably needs fsync()s too, to make sure all error cases get flagged up. At the least it should unmount the metafs before bailing out in all cases.

Nate, could you open a separate bz for the fsck.gfs2 failure?

Comment 5 Abhijith Das 2020-05-11 16:30:51 UTC
Created attachment 1687379 [details]
Revised patch - moved error handling fixes to another patch

Comment 6 Abhijith Das 2020-05-11 16:32:42 UTC
Created attachment 1687380 [details]
First bash at error handling fixes

Andy, when you get a chance, could you go over this (and the previous) patch and let me know if it looks ok to you?

Comment 7 Andrew Price 2020-05-11 17:23:49 UTC
(In reply to Abhijith Das from comment #6)
> Created attachment 1687380 [details]
> First bash at error handling fixes

Just some minor style/maintainability nits - using "close" as a label can make it difficult to search for close() calls later, and returning errno where the caller isn't expecting an errno value can be confusing... returning -1 will probably be safer in those cases. Other than that it looks like a good improvement, thanks Abhi.

Comment 8 Abhijith Das 2020-05-11 23:07:49 UTC
Created attachment 1687481 [details]
Revised error handling cleanup patch

This version has Andy's suggested fixes. Here's a build with this patch and the previous bugfix patch: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=28499297

Comment 9 Andrew Price 2020-05-12 09:31:54 UTC
I've pushed the patches upstream (commits deb620675, bb22cafab) with a slight tweak to the second patch to clear up these warnings:

main_jadd.c:518:12: warning: unused variable ‘blk_addr’ [-Wunused-variable]
  518 |   uint64_t blk_addr = 0;
      |            ^~~~~~~~
main_jadd.c:618:19: warning: too many arguments for format [-Wformat-extra-args]
  618 |   fprintf(stderr, "%s: not a mounted gfs2 file system\n",
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Let me know when you're happy for them to be added to the RHEL package (move the bug to POST) and please make any further fixes on top of the master branch. Thanks!

Comment 10 Andrew Price 2020-06-09 14:37:05 UTC
Covscan found some minor issues in gfs2_jadd so the RHEL8 gfs2-utils build didn't pass gating. I've sent an addendum patch upstream to fix it up and I'll integrate it once it's pushed.

Comment 11 Andrew Price 2020-06-10 11:26:41 UTC
(In reply to Andrew Price from comment #10)
> Covscan found some minor issues in gfs2_jadd so the RHEL8 gfs2-utils build
> didn't pass gating.

Correction: the covscan warnings didn't prevent the build from passing gating. Since the issues it found are minor and not actual bugs I'm pushing this along.

https://brewweb.engineering.redhat.com/brew/buildinfo?buildID=1221688

Comment 14 Nate Straz 2020-08-12 14:14:18 UTC
Verified with gfs2-utils-3.2.0-9.el8.x86_64

SCENARIO - [jadd_no_space]
Creating 1G LV jadded on host-140
Creating file system on /dev/fsck/jadded with options '-p lock_nolock -j 1 -J 128' on host-140
It appears to contain an existing filesystem (gfs2)
/dev/fsck/jadded is a symbolic link to /dev/dm-2
This will destroy any data on /dev/dm-2
Discarding device contents (may take a while on large devices): Done
Adding journals: Done
Building resource groups: Done
Creating quota file: Done
Writing superblock and syncing: Done
Device:                    /dev/fsck/jadded
Block size:                4096
Device size:               1.00 GB (262144 blocks)
Filesystem size:           1.00 GB (262142 blocks)
Journals:                  1
Journal size:              128MB
Resource groups:           5
Locking protocol:          "lock_nolock"
Lock table:                ""
UUID:                      10b06c03-8a46-42d5-ab3c-f25be8a8ecb8
Mounting gfs2 /dev/fsck/jadded on host-140 with opts ''
Filling some space
Try to add more journals than there is space
Failed to add journals: No space left on device

Insufficient space on the device to add 5 128MB journals (1MB QC size)

Required space  :     165465 blks (33093 blks per journal)
Available space :     100745 blks

Good, no gfs2meta mounts found
Unmounting /mnt/fsck on host-140
Removing LV jadded on host-140

Comment 17 errata-xmlrpc 2020-11-04 02:01:07 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory (gfs2-utils bug fix and enhancement update), and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2020:4550