Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 09 Nov 2015 11:09:18 -0800
From:      John Baldwin <jhb@freebsd.org>
To:        Julian Elischer <julian@freebsd.org>
Cc:        Kirk McKusick <mckusick@mckusick.com>, "freebsd-fs@freebsd.org" <freebsd-fs@freebsd.org>, 'Jilles Tjoelker' <jilles@stack.nl>
Subject:   Re: futimens and utimensat vs birthtime (resurected)
Message-ID:  <10503657.4i3LlcO4Z3@ralph.baldwin.cx>
In-Reply-To: <56401002.8020909@freebsd.org>
References:  <201508142122.t7ELMPjR002452@chez.mckusick.com> <56401002.8020909@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Monday, November 09, 2015 11:16:18 AM Julian Elischer wrote:
> On 8/15/15 5:22 AM, Kirk McKusick wrote:
> >> From: John Baldwin <jhb@freebsd.org>
> >> To: freebsd-current@freebsd.org
> >> Subject: Re: futimens and utimensat vs birthtime
> >> Date: Fri, 14 Aug 2015 10:39:41 -0700
> >> Cc: "freebsd-fs@freebsd.org" <freebsd-fs@freebsd.org>,
> >>          "'Jilles Tjoelker'" <jilles@stack.nl>
> >>
> >> On Friday, August 14, 2015 10:46:10 PM Julian Elischer wrote:
> >>> I would like to implement this call. but would like input as to it's
> >>> nature.
> >>> The code inside the system would already appear to support handling
> >>> three elements, though it needs some scrutiny,
> >>> so all that is needed is a system call with the ability to set the
> >>> birthtime directly.
> >>>
> >>> Whether it should take the form of the existing calls but expecting
> >>> three items is up for discussion.
> >>> Maybe teh addition of a flags argument to specify which items are
> >>> present and which to set.
> >>>
> >>> ideas?
> >> I believe these should be new calls.  Only utimensat() provides a flag
> >> argument, but it is reserved for AT_* flags.  I would be fine with
> >> something like futimens3() and utimensat3() (where 3 means "three
> >> timespecs").  Jilles implemented futimens() and utimensat(), so he
> >> might have ideas as well.  I would probably stick the birth time in
> >> the third (final) timespec slot to make it easier to update new code
> >> (you can use an #ifdef just around ts[2] without having to #ifdef the
> >> entire block).
> >>
> > I concur with John's suggestion. Add a new system call with three
> > argument set of times specifying birthtime as the last one. I
> > proposed doing this when I added birthtime, but did not as the
> > sentiment at the time was that it would gratuitously make FreeBSD
> > written applications less portable if they used this new non-standard
> > system call.
> 
> time has passed and I would like to get back to this:
> There was some feedback last time. Taking that into account:
> 
> One problem with the '3 arg' version is that we have to reinvent it 
> again if we get a 4th.
> We could make something like the following:
> 
> It has been suggested that a 4th entry might be "last archive time" 
> and that
> "time created on this filesystem" and "file created first time (ever)" 
> might also
> be separate in some systems. (as examples of why 3 might not be enough)
> 
> the syscall name is also not decided.
> one suggested form is:
> $name (int fd, int32 flags/mask, const struct timespec *arrayptr[]);
> 
> vs the current:
> utimensat(int fd, const char *path, const struct timespec times[2],
>           int flag);
> 
> where mask is:
> ---
> 0x01 disable_heuristic
> 0x02 AT_SYMLINK_NOFOLLOW
> 0x04-0x08 unused
> --  times present---
> 0x10 access time
> 0x20 mod time
> 0x40 birth time
> 0x80 archive time
> 0x100 conception time
> 0x200-on reserverd for future times
> 
> any bit not set in 0x010-on is not represented in the array.
> no bits would be a nop (the price for orthogonality) and would 
> effectively be the same as a test for writeability.
> "disable heuristic" would disable the forcing of birthtime back to mod 
> time or earlier (and any other 'logical fixes')
> setting all 5 'time-present' bits would imply the array has 5 entries.
> 
> anyone care to comment

I think the mask is overly complex.  utimensat() already has UTIME_OMIT.
I think you should just have a new 'count' argument and use UTIME_OMIT
when you wish to leave a timestamp alone:

futimens3(int fd, const struct timespec *times, int ntimes);
utimensat5(int fd, const char *path, const struct timespec *ntimes,
   int ntimes, int flag);

ntimes defines how many valid timespecs are in the times[] array.  If
you pass in fewer entries than is required, any missing entries at the
end are treated as if they were set to UTIME_OMIT (so not modified).
The new versions would not set birthtime implicitly.  For now I would
simply define birthtime as times[2].  One curious idea is if you wanted
to permit setting the change time (right now ctime is implicitly updated
to "now" when you set the time).  I think you probably don't want to
allow that.

The only other thing you might consider is adding constants for the
array indices which might help with portability if other systems adopt
this interface:

#define TIMENS_ACCESS          0
#define TIMENS_MODIFICATION    1
#define TIMENS_BIRTH           2
#define TIMENS_MAX			TIMENS_BIRTH

This would let you do things like in portable-ish code (if the
interface itself is more widely adopted) where different systems can
define the layout of the array while keeping the API portable.

	struct timespec times[TIMENS_MAX];

	for (i = 0; i < nitems(times); i++)
		times[i].tv_usec = UTIME_OMIT;
#ifdef TIMENS_BIRTH
	timens[TIMENS_BIRTH] = foo;
#endif
	futimens4(fd, times, nitems(times));

-- 
John Baldwin



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?10503657.4i3LlcO4Z3>