Subject: Re: bug#38435: BTRFS open_ctree failed

From: Guillaume Le Vaillant <[email-masked]>
Date: Sat, 30 Nov 2019 17:01:08 +0100

Guillaume Le Vaillant skribis:

> raingloom skribis:
>
>> This is what I get after a recent `guix system reconfigure` :
>> Scanning for Btrfs filesystems
>> [    2.342790] BTRFS error (device sda1): open_ctree failed
>>
>> Previous profiles work, I haven't modified anything about my config.scm
>> between them.
>>
>> [...]
>>
>>
>> Contents of /etc/profile.scm:
>>
>> [...]
>>
>>   (file-systems (cons* (file-system
>>                          (device (file-system-label "GUIX"))
>>                          (mount-point "/")
>> 			 (options "lazytime,compress")
>>                          (type "btrfs"))
>>                        ;(file-system
>>                        ;  (device (uuid "1234-ABCD" 'fat))
>>                        ;  (mount-point "/boot/efi")
>>                        ;  (type "vfat"))
>>                        %base-file-systems))
>>
>
> I just tried adding the 'lazytime' option to my root file system, and
> I got the same error as you when booting. Could you try removing it and
> see if it works?
>
> Until recently, the options declared in 'file-system' records were
> always ignored when mounting the root file system. Now they are taken
> into consideration, and I think it reveals a bug in the way file systems
> are mounted. If some options like 'lazytime' or 'defaults' are declared
> in a 'file-system' record (root file system or not), mounting it fails.
> However some other options like 'compress' or 'autodefrag' work fine.
>
> I suspect Guix adds some options by default when trying to mount file
> systems, and maybe we end up with conflicting options or doubled options
> that cause problems.

Apparently, Guix uses the 'mount' system call directly to mount file
systems (c.f. 'guix/build/syscalls.scm'), and passes all the options
declared in the 'file-system' records in the 'data' argument.

However the man page for mount(2) indicates:

--8<---------------cut here---------------start------------->8---
int mount(const char *source, const char *target,
                const char *filesystemtype, unsigned long mountflags,
                const void *data);

[...]

The data argument is interpreted by the different filesystems.
Typically it is a string of comma-separated options understood by this
filesystem.  See mount(8) for details of the options available for each
filesystem type.
--8<---------------cut here---------------end--------------->8---

If I understand correcly, the generic options (e.g. 'lazytime') must be
passed in 'mountflags', and the options specific to the file system
(e.g. 'compress') must be passed in 'data'.

This would mean that before calling the 'mount' system call, we must
remove the generic options from the 'options' variable (which is then
passed in 'data'), and add their corresponding flags to the 'flags'
variable (which is then passed in 'mountflags').

What do you think?