This is an update to Arnd Bergmann's RFC patch series: https://lkml.org/lkml/2014/5/30/669 .
The syscalls and runtime libraries will be handled in separate patch series.
The filling of max and min timestamps for individual filesystems can be leveraged from the patch series: https://lkml.org/lkml/2015/11/20/413 1. Objective: To transition all file system code to use 64 bit time. This translates to using timespec64 across the fs code for any timestamp representation.
2. Problem Description: struct timespec cannot represent times after year 2038 on 32 bit systems. The alternative to timespec in the kernel world is timespec64 to get around the above problem. This will be the UAPI exposed interface.
3. Design objectives: The goal of this approach was to come up with small manageable patches to address the above problem. Preferably, a single patch per filesystem that can be merged independently.
Also, a more generic approach that all the individual filesystems could follow was preferred.
4. Solution: The solution incorporated in the patch series involves stages defined below:
4.1. CONFIG_FS_USES_64BIT_TIME This new config is defined to #ifdef code that is required to support 64 bit times. 4.2. struct inode times: The struct inode saves {a,c,m}timestamps as struct timespec. This leads to 2 problems: a. The size of the structure depends on whether the machine is 32/ 64 bit. b. y2038 problem described above. struct timespec64 also has the same problem as in (a) above. Choosing scalar types to store these timestamps(time64 and s32) solves both the above problems. Adding accessors to access these timestamps would hide the internal data type so that this can be changed according to config in (4.1). 4.3. struct inode_timespec: Use inode_timespec for all other timestamp representation throughout VFS and individual filesystems. inode_timespec is aliased to timespec or timespec64 based on config defined in (4.1). Using timespec64 in this stage would require ifdef-ing the code, which is spread throughout the code. 4.4. Enable config in (4.1).
4.5. Convert inode_timespec to timespec64: Drop all references to inode_timespec in (4.3). Replace it with timespec64. 5. Alternate Solution: Steps involved are:
5.1. Change VFS code to handle both timespec64 and timespec: There are a few API's in the VFS that take timestamps as arguments: generic_update_time(), inode->i_op->update_time(), lease_get_mtime(), fstack_copy_attr_all(), setattr_copy(), generic_fillattr. The attr and kstat properties could have accessors like inode. But, the other functions will have to maintain copies or be updated simultaenously along with other affecting filesystems.
5.2.struct timespec64: Change individual fs to use timespec64.
5.3. struct inode times: The struct inode saves {a,c,m}timestamps as struct timespec.
This leads to 2 problems: a. The size of the structure depends on whether the machine is 32/ 64 bit. b. y2038 problem described above.
struct timespec64 also has the same problem as in (a) above. Choosing scalar types to store these timestamps(time64 and s32) solves both the above problems.
Change individual filesystems to use macros to access inode times. Inode macros can assume conversion from timespec64 always.
5.4. VFS: Change vfs code also as above in (1) and (2).
5.5. Drop timespec This involves dropping support for any api/ struct changes to make vfs use only timespec64 for timestamps.
6. Rationale: The advantage of the method described in (5) is that we do not have inode_timespec aliases only to be dropped later.
But, the method suffers from disadvantages: a. As mentioned in (5.1), our process is affected as all the filesystems using each api must be changed simultaenously or VFS should have a copy. b. While individual filesystems are being changed, VFS will have to have 2 copies of a few apis. This will mean that at this time, any new code being added might use either. This might lead to confusion.
Misc: 7. Range check: Patches include range check and clamping of timestamps. This topic did not have a conclusion on the previous RFC.
7.1. Rationale The method incorporated in the patch series is based on following principles: a. Linux does not impose any fixed format for on-disk inodes. LKML discussion is still ongoing concerning the best handling of file systems used or updated after their expiration date. b. Linux cannot surmise the side effects to a file system because of the wrong timestamps as each fs saves timestamps differently. c. Individual filesystems must be able to say what to do when timestamps are clamped.
7.2. Solution Based on the above principles, the solution is described below:
7.2.1. There are 2 instances that the solution handles differently: a. While mounting a filesystem: A filesystem that has already exceeded the range of its timestamp fields. b. While doing operations on a mounted filesystem: Timestamps start getting clamped after the filesystem is mounted.
7.2.2. In both the above cases, a function is invoked as per the callbacks registered by filesystems.
8. Testing This is a proof of concept implementation. I want to get some feedback before I convert rest of the file systems.
I've done some initial testing based on the patches below on x86 64 bit arch. Testing was mainly done on the root filesystem. mount, stat, touch, read, write system calls were used for testing timestamp clamps and other functionality.
Patches 8-15 are only included to provide a complete picture.
Deepa Dinamani (15): fs: add Kconfig entry CONFIG_FS_USES_64BIT_TIME vfs: Change all structures to support 64 bit time kernel: time: Add macros and functions to support 64 bit time vfs: Add support for vfs code to use 64 bit time fs: cifs: Add support for cifs to use 64 bit time fs: fat: convert fat to 64 bit time fs: ext4: convert to use 64 bit time fs: Enable 64 bit time fs: cifs: replace inode_timespec with timespec64 fs: fat: replace inode_timespec with timespec64 fs: ext4: replace inode_timespec with timespec64 vfs: remove inode_timespec and timespec references kernel: time: change inode_timespec to timespec64 vfs: Remove inode_timespec aliases fs: Drop CONFIG_FS_USES_64BIT_TIME
fs/attr.c | 15 ++--- fs/bad_inode.c | 10 ++- fs/binfmt_misc.c | 7 +- fs/cifs/cache.c | 16 +++-- fs/cifs/cifsencrypt.c | 2 +- fs/cifs/cifsglob.h | 6 +- fs/cifs/cifsproto.h | 9 +-- fs/cifs/cifssmb.c | 17 +++-- fs/cifs/file.c | 9 ++- fs/cifs/inode.c | 65 ++++++++++++------- fs/cifs/netmisc.c | 26 ++++---- fs/ext4/acl.c | 3 +- fs/ext4/ext4.h | 44 +++++++------ fs/ext4/extents.c | 25 ++++++-- fs/ext4/ialloc.c | 9 ++- fs/ext4/inline.c | 10 ++- fs/ext4/inode.c | 16 +++-- fs/ext4/ioctl.c | 16 +++-- fs/ext4/namei.c | 40 ++++++++---- fs/ext4/super.c | 6 +- fs/ext4/xattr.c | 2 +- fs/fat/dir.c | 7 +- fs/fat/fat.h | 8 ++- fs/fat/file.c | 10 ++- fs/fat/inode.c | 46 ++++++++++---- fs/fat/misc.c | 7 +- fs/fat/namei_msdos.c | 40 +++++++----- fs/fat/namei_vfat.c | 41 ++++++++---- fs/inode.c | 53 +++++++++++----- fs/libfs.c | 50 ++++++++++++--- fs/locks.c | 5 +- fs/nsfs.c | 6 +- fs/pipe.c | 6 +- fs/posix_acl.c | 2 +- fs/stack.c | 6 +- fs/stat.c | 6 +- fs/super.c | 10 +++ fs/utimes.c | 6 +- include/linux/fs.h | 101 +++++++++++++++++++++++++---- include/linux/fs_stack.h | 9 +-- include/linux/stat.h | 6 +- include/linux/time64.h | 4 ++ kernel/time/time.c | 162 ++++++++++++++++++++++++++++++++++++++++++----- 43 files changed, 691 insertions(+), 253 deletions(-)