[PATCH v6] linux: Add openat2 (BZ 31664)

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Tue Nov 18 19:37:09 GMT 2025



On 18/11/25 16:09, Paul Eggert wrote:
> Thanks for bird-dogging this. Here are some comments about the documentation. To some extent they're also comments on the man page that the documentation is derived from, but I'll focus on the glibc manual.
> 
> On 2025-11-10 08:19, Adhemerval Zanella wrote:
> 
>> +The @code{open_how} structure describes how to open a file using @code{openat2}.
>> +
>> +@strong{Portability note:} In the future, additional fields can be added
>> +to @code{struct open_how} at the end, so that the size of this data
>> +type changes.  Do not use it in places where this matters, such as
>> +structure fields in installed header files, where such a change could
>> +affect the application binary interface (ABI).
> 
> Remove "at the end" (since in theory new fields could be added in the middle so long as existing field offsets are not changed), and change "changes" to "increases" (since the size cannot decrease).

Ack.

> 
> 
>> +Unlike @code{openat}, @code{openat2} returns an error for unknown
>> +or conflicting values.
>> +
>> +@item mode
>> +This field specifies the mode for the new file, similar to @code{mode}
>> +argument of @code{openat}.  Unlike @code{openat}, @code{openat2}
>> +returns an error for invalid values (i.e., values greater than @code{07777}).
> Sometimes openat does return an error for unknown or conflicting flags (e.g., O_RDONLY | O_TMPFILE). And sometimes openat2 does not (e.g., O_RDONLY | O_APPEND) - though admittedly it is undocumented and unclear whether values are "conflicting". What's actually happening, is that openat2 is stricter than openat. So let's document it that way, by rewording to something like the following:
> 
> @code{openat2} is stricter than @code{openat} in rejecting unknown or
> conflicting values. For example, @code{openat2} rejects a mode that
> exceeds 07777, whereas @code{openat} silently ignores
> excess high-order bits.

Ack.

> 
> @item mode
> This field specifies the mode for the new file, similar to @code{mode}
> argument of @code{openat}. It should be in the range 0..07777.
> 
>> +@item RESOLVE_BENEATH
>> +Do not permit the path resolution to succeed if any component of the
>> +resolution is not a descendant of the directory indicated by @var{dirfd}.
>> +This causes absolute symbolic links and absolute values of @var{pathname}
>> +to be reject.
> 
> The last sentence is incomplete and ungrammatical. Reword to:
> 
> This rejects absolute pathnames, pathnames containing @file{..}@:
> components that would be resolved relative to @var{dfd},
> and symbolic links that resolve to pathnames that would be rejected.
> The rejection occurs even if @var{dfd} is the root directory.
> 
> 

Ack.

>> +@item RESOLVE_IN_ROOT
>> +Treat the directory referred to by @var{dirfd} as the root directory
>> +while resolving the @var{pathname}.
>> +Absolute symbolic links and absolute values of @var{pathnames} are
>> +interpreted relative to @var{dirfd}.
> 
> The last sentence is incomplete as it does not mention "..". Reword to:
> 
> Treat absolute pathnames as being relative to @var{dfd},
> treat a @file{..}@: component as being equivalent to @file{.}@:
> if it is resolved relative to @var{dfd},
> and treat symbolic link contents consistently with this.

Ack.

> 
> 
>> +@item RESOLVE_CACHED
>> +Make the open operation fail unless all path components are already
>> +present in the kernel's lookup cache.
> 
> I have no idea why an application would want to use this flag.
> Please add a cogent explanation for why it's useful.

I am not sure either, so I used the documentation from man-pages.  The
kernel does not have any self-test using this flag either. I don't have
a strong opinion here, where either we just skip this from documentation
or use this generic explanation.

> 
> 
>> +For additional information, consult the manual page @manpageurl{openat2,2}.
>> +@xref{Linux Kernel}.
> 
> Please remove this, and put any such additional information (what is it?) into the glibc manual.

I followed what we did for sched_setattr and sched_getattr (21571ca0d70302909cf72707b2a7736cf12190a0)
where the documentation mostly defers to the Linux manual pages. And I really
prefer to rely on it as the authoritative documentation for Linux specific
syscalls. 

> 
> 
>> +@deftypefun int openat2 (int @var{dirfd}, const char *restrict @var{pathname}, const struct open_how *restrict @var{how}, size_t @var{size})
> 
> Now that all pointer arguments are pointer-to-const, there is no need for 'restrict'. The situation is similar to utimensat.
> 
> 

Ack.

>> For portability
>> +to future API versions that extend @code{struct open_how}, @code{*@var{how}}
>> +should be initialized either by a struct initializer or by @code{memset} to zero.
> 
> There are other ways to fully initialize *how, e.g., via structure assignment from a fully-initialized structure, or by being in static storage that is initialized to zero. So please change to:
> 
> For portability to future API versions that may extend
> @code{struct open_how}, @code{*@var{how}} should be fully initialized,
> e.g., by a struct initializer, by @code{memset} to zero,
> or by having static storage duration.

Ack, I used the same text from sched_setattr and sched_getattr (21571ca0d70302909cf72707b2a7736cf12190a0).

> 
> 
>> +On failure, @code{openat2} returns @math{-1} and sets @code{errno}. It can
>> +fail for any of the reasons @code{openat} fails, plus the following reasons:
>> +
>> +@table @code
>> +@item E2BIG
>> +An extension that the kernel does not support was specified in @code{*@var{how}},
>> +or a larger struct was used with non-zero members.
> 
> I don't see the former in the kernel source code. Also, a struct that's waaay too large (bigger than a page size) also gets E2BIG. So, change to something like this:
> 
> @var{size} is too large for any future extension,
> or @code{*@var{how}} contains non-zero members
> that are future extensions not supported by this kernel.
> 

Ack.

> 
>> +@item EAGAIN
>> +@code{@var{how}->resolve} contains either RESOLVE_IN_ROOT or RESOLVE_BENEATH, and
>> +the kernel could not ensure that @code{".."} component did not escape.  Or
>> +@code{RESOLVE_CACHED} was set, and the open operation cannot be performed
>> +using only cached information.
> 
> This requires more explanation. How can the kernel not know whether ".." escapes? Please give a scenario.
> 

As for RESOLVE_CACHED, I am relying on man-pages explanation here.  I don't
think I have added a testcase for this specific, so I think would be better
to just remove this.

> 
>> +It can also return all the errors @code{openat} returns, or other errors
>> +due to new members added by the kernel.
> 
> The "other errors" can occur only if *how is not properly initialized, right? If so, please say so; if not, please remove the "other errors" clause.
> 

Ack.

> 
>> +extern int openat2 (int __dfd, const char *__restrict __filename,
>> +            const struct open_how *__restrict __how,
>> +            size_t __usize)
>> +     __nonnull ((2, 3));
> 
> No need for the two "__restrict"s.
> 

Ack.


More information about the Libc-alpha mailing list