[Bug 271925] chflags(1) fails to remove uarch flag with hardlinked files (ZFS)

From: <bugzilla-noreply_at_freebsd.org>
Date: Fri, 23 Jun 2023 01:03:14 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=271925

--- Comment #5 from Jamie Landeg-Jones <jamie@catflap.org> ---

(In reply to Stefan Eßer from comment #1)

TThanks for the quick response!
Apologies for the late reply, I haven't been at home for the last 2 weeks, so
online time is more sporadic.

The problem with /bin/chflags is more generic - it's just that this ZFS quirk
highlighted the difference. The more general case is that whilst /bin/chflags
will not modify a file if the modification isn't needed, the logic fails when
files are hardlinked... Though fixing this may be not worth the effort, it's
just pedantry at the end of the day, and might even be considered "correct"
behaviour - i.e. "if a file is hardlinked then expect it to be accessed for
each link found."

Anyway, if it was fixed, I think filtering out duplicate inodes would be the
cleanest and most efficient solution.

For example, (and I forgot to mention in my post, sorry) I did a quick
chflags(2) syscall wrapper code to set the flags on a file to 0:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <err.h>
#include <errno.h>
#include <sys/stat.h>

int main (int argc, char **argv)
  {
    while (*++argv != NULL)
      if (lchflags (*argv, 0) == -1)
        warnx("%s: %s", *argv, strerror (errno));
  }

On tmpfs, UFS, and ZFS,touching a test file, and setting some flags, then
running the above program resets the flags, and updates ctime, as expected.

On all three filesystems, running it again always updates the ctime on all 3
filesystems, but on ZFS it switches on uarch. Running it again switches off
uarch.

Using /bin/chflags, on all three filesystems, running it again doesn't update
the ctime, or on ZFS, toggle the uarch.

So the consensus seems to be "chflags(2)" updates regardless, whilst
/bin/chflags will stat the file and only make the chflags(2) call if necessary
(of course, this gets tripped up in the hardlinked case mentioned in this bug
report)

> This seems to be caused by ZFS collecting multiple flag updates and by effectively mapping the setting of flags to toggling of flags.

I don't think it's that - try the above test program - whilst filesystems have
the logic "any change updates the ctime", ZFS has the additional "any change
other than one that unsets uarch will also set uarch" - this seems to break
down because when you attempt to remove uarch on a file that doesn't have uarch
set, this fails the "we are removing uarch" logic. This, I suspect, should be
fixed in ZFS.

>  but I guess that the second call sees that the new attributes are identical to the (already altered) current attributes of the file and then marks it to not need a vnode update on stable storage.

I think it's the other way around. The chflags system call (and therefore ZFS)
run the code even if the attributes are identical.
/bin/chflags doesn't run the call if the new attributes are identical, but this
logic fails if a file is hardlinked, because the initial stat shows "both" need
to be updated,

There are also consistencies in chmod(1) - chmod on ZFS causes an update even
if no actual chmod takes place - i haven't looked more closely at this, but
this opens up a whole can of worms.

I guess the first question should be "If any metdata change is attempted on a
file that doesn't actually result in the data being changed (because it's
"changing" it to the value it already has) then whose responsibility is it to
not attempt the change, and consequently update ctime?

Is it userland, or is it the syscall, or is it the filesystem code itself?

Cheers, Jamie

-- 
You are receiving this mail because:
You are the assignee for the bug.