Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1274142 > unrolled thread
| Started by | David Howells <dhowells@redhat.com> |
|---|---|
| First post | 2015-11-20 16:00 +0100 |
| Last post | 2015-11-24 21:30 +0100 |
| Articles | 20 on this page of 31 — 11 participants |
Back to article view | Back to linux.kernel
[RFC][PATCH 00/12] Enhanced file stat system call David Howells <dhowells@redhat.com> - 2015-11-20 16:00 +0100
[PATCH 04/12] statx: AFS: Return enhanced file attributes David Howells <dhowells@redhat.com> - 2015-11-20 16:00 +0100
[PATCH 11/12] fsinfo: NFS: Return information through the filesystem info syscall David Howells <dhowells@redhat.com> - 2015-11-20 16:00 +0100
[PATCH 07/12] statx: CIFS: Return enhanced attributes David Howells <dhowells@redhat.com> - 2015-11-20 16:00 +0100
Re: [PATCH 07/12] statx: CIFS: Return enhanced attributes Steve French <smfrench@gmail.com> - 2015-11-24 18:40 +0100
[PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding David Howells <dhowells@redhat.com> - 2015-11-20 16:00 +0100
Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding Andreas Dilger <adilger@dilger.ca> - 2015-11-24 18:40 +0100
Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding Theodore Ts'o <tytso@mit.edu> - 2015-11-24 20:40 +0100
Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding Arnd Bergmann <arnd@arndb.de> - 2015-11-24 21:20 +0100
Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding Theodore Ts'o <tytso@mit.edu> - 2015-11-29 03:50 +0100
Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding Arnd Bergmann <arnd@arndb.de> - 2015-11-29 22:40 +0100
Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding Theodore Ts'o <tytso@mit.edu> - 2015-11-30 15:20 +0100
Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding Arnd Bergmann <arnd@arndb.de> - 2015-11-30 15:40 +0100
Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding Elmar Stellnberger <estellnb@elstel.org> - 2015-11-30 16:00 +0100
Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding David Howells <dhowells@redhat.com> - 2015-11-26 16:30 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call Martin Steigerwald <martin@lichtvoll.de> - 2015-11-20 17:30 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call David Howells <dhowells@redhat.com> - 2015-11-20 17:30 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call Martin Steigerwald <martin@lichtvoll.de> - 2015-11-20 17:40 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call bfields@fieldses.org (J. Bruce Fields) - 2015-11-25 19:00 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call Andreas Dilger <adilger@dilger.ca> - 2015-11-25 20:40 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call Christoph Hellwig <hch@infradead.org> - 2015-11-24 09:20 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call Martin Steigerwald <martin@lichtvoll.de> - 2015-11-24 09:50 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call Christoph Hellwig <hch@infradead.org> - 2015-11-24 10:00 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call Casey Schaufler <casey@schaufler-ca.com> - 2015-11-20 18:00 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call Christoph Hellwig <hch@infradead.org> - 2015-11-24 09:20 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call Casey Schaufler <casey@schaufler-ca.com> - 2015-11-24 16:00 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call Andreas Dilger <adilger@dilger.ca> - 2015-11-24 17:30 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call Christoph Hellwig <hch@infradead.org> - 2015-11-24 09:20 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call David Howells <dhowells@redhat.com> - 2015-11-26 16:20 +0100
Re: [RFC][PATCH 00/12] Enhanced file stat system call Andreas Dilger <adilger@dilger.ca> - 2015-11-26 23:10 +0100
Re: [PATCH 03/12] statx: Add a system call to make enhanced file info available Dave Chinner <david@fromorbit.com> - 2015-11-24 21:30 +0100
Page 1 of 2 [1] 2 Next page →
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2015-11-20 16:00 +0100 |
| Subject | [RFC][PATCH 00/12] Enhanced file stat system call |
| Message-ID | <qwVkl-6h-3@gated-at.bofh.it> |
Implement new system calls to provide enhanced file stats and enhanced
filesystem stats. The patches can be found here:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=xstat
===========
DESCRIPTION
===========
The third patch provides this new system call:
long ret = statx(int dfd,
const char *filename,
unsigned atflag,
unsigned mask,
struct statx *buffer);
This is an enhanced file stat function that provides a number of useful
features, in summary:
(1) More information: creation time, data version number,
flags/attributes. A subset of these is available through a number of
filesystems (such as CIFS, NFS, AFS, Ext4 and BTRFS).
(2) Lightweight stat (AT_NO_ATTR_SYNC): Ask for just those details of
interest, and allow a network fs to approximate anything not of
interest, without going to the server.
(3) Heavyweight stat (AT_FORCE_ATTR_SYNC): Force a network fs to flush
buffers and go to the server, even if it thinks its cached attributes
are up to date.
(4) Allow the filesystem to indicate what it can/cannot provide: A
filesystem can now say it doesn't support a standard stat feature if
that isn't available.
(5) Make the fields a consistent size on all arches, and make them large.
(6) Can be extended by using more request flags and using up the padding
space in the statx struct.
Note that no lstat() equivalent is required as that can be implemented
through statx() with atflag == 0. There is also no fstat() equivalent as
that can be implemented through statx() with filename == NULL and the
relevant fd passed as dfd.
The seventh patch provides another new system call:
long ret = fsinfo(int dfd,
const char *filename,
unsigned atflag,
unsigned request,
void *buffer);
This is an enhanced filesystem stat and information retrieval function that
provides more information, in summary:
(1) All the information provided by statfs() and more. The fields are
made large.
(2) Provides information about timestamp range and resolution to
complement statx().
(3) Provides information about IOC flags supported in statx()'s return.
(4) Provides volume binary IDs and UUIDs.
(5) Provides the filesystem name according to the kernel as a string
(eg. "ext4" or "nfs3") in addition to the magic number.
(6) Provides information obtained from network filesystems, such as volume
and domain names.
(7) Has lots of spare space that can be used for future extenstions and a
bit mask indicating what was provided.
Note that I've added a 'request' identifier. This is to select the set of
data to be returned. The idea is that 'buffer' points to a fixed-size
struct selected by request. Currently only 0 is available and this refers
to 'struct fsinfo'. However, I could split up the buffer into say 3:
(0) statfs-type information
(1) Timestamp and IOC flags info.
(2) Network fs strings.
However, some of this might be better retrieved through getxattr().
=======
TESTING
=======
Test programs are added into samples/statx/ by the appropriate patches.
David
---
David Howells (12):
Ext4: Fix extended timestamp encoding and decoding
statx: Provide IOC flags for Windows fs attributes
statx: Add a system call to make enhanced file info available
statx: AFS: Return enhanced file attributes
statx: Ext4: Return enhanced file attributes
statx: NFS: Return enhanced file attributes
statx: CIFS: Return enhanced attributes
fsinfo: Add a system call to make enhanced filesystem info available
fsinfo: Ext4: Return information through the filesystem info syscall
fsinfo: AFS: Return information through the filesystem info syscall
fsinfo: NFS: Return information through the filesystem info syscall
fsinfo: CIFS: Return information through the filesystem info syscall
arch/x86/entry/syscalls/syscall_32.tbl | 2
arch/x86/entry/syscalls/syscall_64.tbl | 2
fs/afs/inode.c | 23 ++
fs/afs/super.c | 39 ++++
fs/cifs/cifsfs.c | 25 +++
fs/cifs/cifsfs.h | 4
fs/cifs/cifsglob.h | 8 +
fs/cifs/dir.c | 2
fs/cifs/inode.c | 124 ++++++++++---
fs/cifs/netmisc.c | 4
fs/exportfs/expfs.c | 4
fs/ext4/ext4.h | 24 ++-
fs/ext4/file.c | 2
fs/ext4/inode.c | 31 +++
fs/ext4/namei.c | 2
fs/ext4/super.c | 39 ++++
fs/ext4/symlink.c | 2
fs/nfs/inode.c | 45 ++++-
fs/nfs/internal.h | 1
fs/nfs/nfs4super.c | 1
fs/nfs/super.c | 58 ++++++
fs/ntfs/time.h | 2
fs/stat.c | 305 +++++++++++++++++++++++++++++---
fs/statfs.c | 218 +++++++++++++++++++++++
include/linux/fs.h | 7 +
include/linux/stat.h | 14 +
include/linux/syscalls.h | 6 +
include/linux/time64.h | 2
include/uapi/linux/fcntl.h | 2
include/uapi/linux/fs.h | 7 +
include/uapi/linux/stat.h | 185 +++++++++++++++++++
samples/Makefile | 3
samples/statx/Makefile | 13 +
samples/statx/test-fsinfo.c | 179 +++++++++++++++++++
samples/statx/test-statx.c | 273 +++++++++++++++++++++++++++++
35 files changed, 1558 insertions(+), 100 deletions(-)
create mode 100644 samples/statx/Makefile
create mode 100644 samples/statx/test-fsinfo.c
create mode 100644 samples/statx/test-statx.c
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2015-11-20 16:00 +0100 |
| Subject | [PATCH 04/12] statx: AFS: Return enhanced file attributes |
| Message-ID | <qwVkm-6h-37@gated-at.bofh.it> |
| In reply to | #1274142 |
Return enhanced file attributes from the AFS filesystem. This includes the
following:
(1) The data version number as st_version, setting STATX_VERSION.
(2) STATX_INFO_AUTOMOUNT will be set on automount directories by virtue of
S_AUTOMOUNT being set on the inode. These are referrals to other
volumes or other cells.
(3) STATX_INFO_AUTODIR on a directory that does cell lookup for
non-existent names and mounts them (typically mounted on /afs with -o
autocell). The resulting directories are marked STATX_INFO_FABRICATED
as they do not actually exist in the mounted AFS directory.
(4) Files, directories and symlinks accessed over AFS are marked
STATX_INFO_REMOTE. Local fake directories are marked
STATX_INFO_FABRICATED.
(5) STATX_INFO_NONSYSTEM_OWNERSHIP is set as the UID and GID retrieved
from an AFS share may not be applicable on the system.
STATX_ATIME, STATX_CTIME and STATX_BLOCKS are cleared as AFS does not
support them.
Example output:
[root@andromeda ~]# ./samples/statx/test-statx /afs
statx(/afs) = 0
results=7ef
Size: 2048 Blocks: 0 IO Block: 4096 directory
Device: 00:25 Inode: 1 Links: 2
Access: (0777/drwxrwxrwx) Uid: 0 Gid: 0
Access: 2006-05-07 00:21:15.000000000+0100
Modify: 2006-05-07 00:21:15.000000000+0100
Change: 2006-05-07 00:21:15.000000000+0100
IO-blocksize: blksize=4096
Signed-off-by: David Howells <dhowells@redhat.com>
---
fs/afs/inode.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index e06f5a23352a..dcf0338ea5cc 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -71,9 +71,9 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
inode->i_uid = vnode->status.owner;
inode->i_gid = GLOBAL_ROOT_GID;
inode->i_size = vnode->status.size;
- inode->i_ctime.tv_sec = vnode->status.mtime_server;
- inode->i_ctime.tv_nsec = 0;
- inode->i_atime = inode->i_mtime = inode->i_ctime;
+ inode->i_mtime.tv_sec = vnode->status.mtime_server;
+ inode->i_mtime.tv_nsec = 0;
+ inode->i_atime = inode->i_ctime = inode->i_mtime;
inode->i_blocks = 0;
inode->i_generation = vnode->fid.unique;
inode->i_version = vnode->status.data_version;
@@ -374,8 +374,7 @@ error_unlock:
/*
* read the attributes of an inode
*/
-int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat)
+int afs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
{
struct inode *inode;
@@ -384,6 +383,20 @@ int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
_enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation);
generic_fillattr(inode, stat);
+
+ stat->result_mask &= ~(STATX_ATIME | STATX_CTIME | STATX_BLOCKS);
+ stat->result_mask |= STATX_VERSION;
+ stat->version = inode->i_version;
+
+ if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags))
+ stat->information |= STATX_INFO_AUTODIR;
+
+ if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags))
+ stat->information |= STATX_INFO_FABRICATED;
+ else
+ stat->information |= STATX_INFO_REMOTE;
+
+ stat->information |= STATX_INFO_NONSYSTEM_OWNERSHIP;
return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2015-11-20 16:00 +0100 |
| Subject | [PATCH 11/12] fsinfo: NFS: Return information through the filesystem info syscall |
| Message-ID | <qwVkn-6h-51@gated-at.bofh.it> |
| In reply to | #1274142 |
Return NFS filesystem information through the filesystem info retrieval
system call. This includes the following:
(1) information about the capacity and resolution of the inode timestamps;
(2) the client hostname as the domain name, setting FSINFO_DOMAIN_NAME;
(3) the remote FSID as the volume ID, setting FSINFO_VOLUME_ID;
and unless AT_NO_ATTR_SYNC is specified:
(4) the statfs information retrieved from the server.
Note that the NFS FSID value is *not* returned as the local FSID since the
FSID value is a local handle used by NFSD; see the volume ID field instead.
Example output:
[root@andromeda ~]# ./test-fsinfo /warthog/
fsinfo(/warthog/) = 0
mask : 12f
dev : 00:27
fs : type=6969 name=nfs4
ioc : 0
nameln: 255
flags : 1020
times : range=8000000000000000-7fffffffffffffff
atime : gran=1e-09s
btime : gran=1e-09s
ctime : gran=1e-09s
mtime : gran=1e-09s
blocks: n=503841 fr=48261 av=22645
files : n=32776192 fr=18903243 av=18903243
bsize : 1048576
frsize: 0
volid : 8c494c34 de5688ac 2e61e05d 5f144b8e
domain: 'warthog'
Note that NFS4 potentially provides a separate value for f_favail that could
be provided through this interface.
Signed-off-by: David Howells <dhowells@redhat.com>
---
fs/nfs/internal.h | 1 +
fs/nfs/nfs4super.c | 1 +
fs/nfs/super.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 60 insertions(+)
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 56cfde26fb9c..6c7bb9c9e5c6 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -442,6 +442,7 @@ extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio);
void nfs_clone_super(struct super_block *, struct nfs_mount_info *);
void nfs_umount_begin(struct super_block *);
int nfs_statfs(struct dentry *, struct kstatfs *);
+int nfs_get_fsinfo(struct dentry *, struct fsinfo *, unsigned);
int nfs_show_options(struct seq_file *, struct dentry *);
int nfs_show_devname(struct seq_file *, struct dentry *);
int nfs_show_path(struct seq_file *, struct dentry *);
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 6fb7cb6b3f4b..1c15c5884ac4 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -54,6 +54,7 @@ static const struct super_operations nfs4_sops = {
.write_inode = nfs4_write_inode,
.drop_inode = nfs_drop_inode,
.statfs = nfs_statfs,
+ .get_fsinfo = nfs_get_fsinfo,
.evict_inode = nfs4_evict_inode,
.umount_begin = nfs_umount_begin,
.show_options = nfs_show_options,
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 383a027de452..bbd33b121b48 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -311,6 +311,7 @@ const struct super_operations nfs_sops = {
.write_inode = nfs_write_inode,
.drop_inode = nfs_drop_inode,
.statfs = nfs_statfs,
+ .get_fsinfo = nfs_get_fsinfo,
.evict_inode = nfs_evict_inode,
.umount_begin = nfs_umount_begin,
.show_options = nfs_show_options,
@@ -494,6 +495,63 @@ int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
EXPORT_SYMBOL_GPL(nfs_statfs);
/*
+ * Read filesystem information.
+ */
+int nfs_get_fsinfo(struct dentry *dentry, struct fsinfo *f, unsigned flags)
+{
+ struct nfs_server *server = NFS_SB(dentry->d_sb);
+ struct nfs_client *client = server->nfs_client;
+ int ret;
+
+ f->f_bsize = dentry->d_sb->s_blocksize;
+ f->f_namelen = server->namelen;
+
+ if (client->rpc_ops->version < 4) {
+ f->f_min_time = 0;
+ f->f_max_time = U32_MAX;
+ } else {
+ f->f_min_time = S64_MIN;
+ f->f_max_time = S64_MAX;
+ }
+
+ f->f_atime_gran_exponent = -6;
+ f->f_ctime_gran_exponent = -6;
+ f->f_mtime_gran_exponent = -6;
+ if (client->rpc_ops->version >= 3) {
+ f->f_atime_gran_exponent = -9;
+ f->f_ctime_gran_exponent = -9;
+ f->f_mtime_gran_exponent = -9;
+ }
+
+ if (client->cl_hostname) {
+ strncpy(f->f_domain_name, client->cl_hostname,
+ sizeof(f->f_domain_name));
+ f->f_domain_name[sizeof(f->f_domain_name) - 1] = 0;
+ f->f_mask |= FSINFO_DOMAIN_NAME;
+ }
+
+ /* Treat the remote FSID as the volume ID since we don't support
+ * reexportation through NFSD.
+ */
+ memcpy(f->f_volume_id, &server->fsid,
+ min(sizeof(f->f_volume_id), sizeof(server->fsid)));
+ f->f_mask |= FSINFO_VOLUME_ID;
+
+ if (flags & AT_NO_ATTR_SYNC)
+ return 0;
+
+ ret = vfs_get_fsinfo_from_statfs(dentry, f, flags);
+ if (ret < 0)
+ return ret;
+
+ /* Don't pass the FSID to userspace since this isn't exportable */
+ memset(&f->f_fsid, 0, sizeof(f->f_fsid));
+ f->f_mask &= ~FSINFO_FSID;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nfs_get_fsinfo);
+
+/*
* Map the security flavour number to a name
*/
static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour)
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2015-11-20 16:00 +0100 |
| Subject | [PATCH 07/12] statx: CIFS: Return enhanced attributes |
| Message-ID | <qwVkn-6h-45@gated-at.bofh.it> |
| In reply to | #1274142 |
Return enhanced attributes from the CIFS filesystem. This includes the
following:
(1) Return the file creation time as btime. We assume that the creation
time won't change over the life of the inode.
(2) Set STATX_INFO_AUTOMOUNT on referral/submount directories.
(3) Unset STATX_INO if we made up the inode number and didn't get it from
the server.
(4) Unset STATX_[UG]ID if we are either returning values passed to mount
and/or the server doesn't return them.
(5) Set STATX_IOC_FLAGS and map various Windows file attributes to
FS_xxx_FL flags in st_ioc_flags, fetching them from the server if we
don't have them yet or don't have a current copy. This includes the
following:
ATTR_READONLY -> FS_IMMUTABLE_FL
ATTR_COMPRESSED -> FS_COMPR_FL
ATTR_HIDDEN -> FS_HIDDEN_FL
ATTR_SYSTEM -> FS_SYSTEM_FL
ATTR_ARCHIVE -> FS_ARCHIVE_FL
(6) Set certain STATX_INFO_xxx to reflect other Windows file attributes:
ATTR_TEMPORARY -> STATX_INFO_TEMPORARY;
ATTR_REPARSE -> STATX_INFO_REPARSE_POINT;
ATTR_OFFLINE -> STATX_INFO_OFFLINE;
ATTR_ENCRYPTED -> STATX_INFO_ENCRYPTED;
(7) Set STATX_INFO_REMOTE on all files fetched by CIFS.
(8) Set STATX_INFO_NONSYSTEM_OWNERSHIP on all files as they all have
Windows ownership details too.
Furthermore, what cifs_getattr() does can be controlled as follows:
(1) If AT_NO_ATTR_SYNC is indicated then this will suppress the flushing
of outstanding writes and the rereading of the inode's attributes with
the server as detailed below.
(2) Otherwise:
(a) If AT_FORCE_ATTR_SYNC is indicated, or mtime, ctime or size are
requested then the outstanding writes will be written to the
server first.
(b) The inode's attributes will be reread from the server:
(i) if AT_FORCE_ATTR_SYNC is indicated;
(ii) if the cached attributes have expired;
(iii) extra attributes are requested that aren't normally stored.
If the inode isn't synchronised, then the cached attributes will be used -
even if expired - without reference to the server. Some attributes may be
unavailable that would otherwise be provided.
Note that cifs_revalidate_dentry() will issue an extra operation to get the
FILE_ALL_INFO in addition to the FILE_UNIX_BASIC_INFO if it needs to
collect creation time and attributes on behalf of cifs_getattr().
[NOTE: THIS PATCH IS UNTESTED!]
Signed-off-by: David Howells <dhowells@redhat.com>
---
fs/cifs/cifsfs.h | 4 +-
fs/cifs/cifsglob.h | 8 +++
fs/cifs/dir.c | 2 -
fs/cifs/inode.c | 124 +++++++++++++++++++++++++++++++++++++++++-----------
4 files changed, 108 insertions(+), 30 deletions(-)
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index c3cc1609025f..fb38d47d84de 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -71,9 +71,9 @@ extern int cifs_rmdir(struct inode *, struct dentry *);
extern int cifs_rename2(struct inode *, struct dentry *, struct inode *,
struct dentry *, unsigned int);
extern int cifs_revalidate_file_attr(struct file *filp);
-extern int cifs_revalidate_dentry_attr(struct dentry *);
+extern int cifs_revalidate_dentry_attr(struct dentry *, bool, bool);
extern int cifs_revalidate_file(struct file *filp);
-extern int cifs_revalidate_dentry(struct dentry *);
+extern int cifs_revalidate_dentry(struct dentry *, bool, bool);
extern int cifs_invalidate_mapping(struct inode *inode);
extern int cifs_revalidate_mapping(struct inode *inode);
extern int cifs_zap_mapping(struct inode *inode);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b406a32deb1f..493e40a15b86 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1152,7 +1152,11 @@ struct cifsInodeInfo {
unsigned long flags;
spinlock_t writers_lock;
unsigned int writers; /* Number of writers on this inode */
+ bool btime_valid:1; /* stored creation time is valid */
+ bool uid_faked:1; /* true if i_uid is faked */
+ bool gid_faked:1; /* true if i_gid is faked */
unsigned long time; /* jiffies of last update of inode */
+ struct timespec btime; /* creation time */
u64 server_eof; /* current file size on server -- protected by i_lock */
u64 uniqueid; /* server inode number */
u64 createtime; /* creation time on server */
@@ -1365,6 +1369,9 @@ struct dfs_info3_param {
#define CIFS_FATTR_NEED_REVAL 0x4
#define CIFS_FATTR_INO_COLLISION 0x8
#define CIFS_FATTR_UNKNOWN_NLINK 0x10
+#define CIFS_FATTR_WINATTRS_VALID 0x20 /* T if cf_btime and cf_cifsattrs valid */
+#define CIFS_FATTR_UID_FAKED 0x40 /* T if cf_uid is faked */
+#define CIFS_FATTR_GID_FAKED 0x80 /* T if cf_gid is faked */
struct cifs_fattr {
u32 cf_flags;
@@ -1382,6 +1389,7 @@ struct cifs_fattr {
struct timespec cf_atime;
struct timespec cf_mtime;
struct timespec cf_ctime;
+ struct timespec cf_btime;
};
static inline void free_dfs_info_param(struct dfs_info3_param *param)
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index c3eb998a99bd..4984f04b0677 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -792,7 +792,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
return -ECHILD;
if (d_really_is_positive(direntry)) {
- if (cifs_revalidate_dentry(direntry))
+ if (cifs_revalidate_dentry(direntry, false, false))
return 0;
else {
/*
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 6b66dd5d1540..fcb024efbd4b 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -166,13 +166,21 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
cifs_nlink_fattr_to_inode(inode, fattr);
inode->i_uid = fattr->cf_uid;
inode->i_gid = fattr->cf_gid;
+ if (fattr->cf_flags & CIFS_FATTR_UID_FAKED)
+ cifs_i->uid_faked = true;
+ if (fattr->cf_flags & CIFS_FATTR_GID_FAKED)
+ cifs_i->gid_faked = true;
/* if dynperm is set, don't clobber existing mode */
if (inode->i_state & I_NEW ||
!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
inode->i_mode = fattr->cf_mode;
- cifs_i->cifsAttrs = fattr->cf_cifsattrs;
+ if (fattr->cf_flags & CIFS_FATTR_WINATTRS_VALID) {
+ cifs_i->cifsAttrs = fattr->cf_cifsattrs;
+ cifs_i->btime = fattr->cf_btime;
+ cifs_i->btime_valid = true;
+ }
if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
cifs_i->time = 0;
@@ -284,18 +292,22 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
u64 id = le64_to_cpu(info->Uid);
if (id < ((uid_t)-1)) {
kuid_t uid = make_kuid(&init_user_ns, id);
- if (uid_valid(uid))
+ if (uid_valid(uid)) {
fattr->cf_uid = uid;
+ fattr->cf_flags |= CIFS_FATTR_UID_FAKED;
+ }
}
}
-
+
fattr->cf_gid = cifs_sb->mnt_gid;
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) {
u64 id = le64_to_cpu(info->Gid);
if (id < ((gid_t)-1)) {
kgid_t gid = make_kgid(&init_user_ns, id);
- if (gid_valid(gid))
+ if (gid_valid(gid)) {
fattr->cf_gid = gid;
+ fattr->cf_flags |= CIFS_FATTR_GID_FAKED;
+ }
}
}
@@ -324,7 +336,8 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
fattr->cf_ctime = CURRENT_TIME;
fattr->cf_mtime = CURRENT_TIME;
fattr->cf_nlink = 2;
- fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
+ fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL |
+ CIFS_FATTR_UID_FAKED | CIFS_FATTR_GID_FAKED;
}
static int
@@ -590,6 +603,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
memset(fattr, 0, sizeof(*fattr));
+ fattr->cf_flags = CIFS_FATTR_WINATTRS_VALID;
fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
if (info->DeletePending)
fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
@@ -601,6 +615,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
+ fattr->cf_btime = cifs_NTtimeToUnix(info->CreationTime);
if (adjust_tz) {
fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
@@ -1887,7 +1902,8 @@ int cifs_revalidate_file_attr(struct file *filp)
return rc;
}
-int cifs_revalidate_dentry_attr(struct dentry *dentry)
+int cifs_revalidate_dentry_attr(struct dentry *dentry,
+ bool want_extra_bits, bool force)
{
unsigned int xid;
int rc = 0;
@@ -1898,7 +1914,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
if (inode == NULL)
return -ENOENT;
- if (!cifs_inode_needs_reval(inode))
+ if (!force && !cifs_inode_needs_reval(inode))
return rc;
xid = get_xid();
@@ -1915,9 +1931,12 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
full_path, inode, inode->i_count.counter,
dentry, dentry->d_time, jiffies);
- if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
+ if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) {
rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
- else
+ if (rc != 0)
+ goto out;
+ }
+ if (!cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext || want_extra_bits)
rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
xid, NULL);
@@ -1940,12 +1959,13 @@ int cifs_revalidate_file(struct file *filp)
}
/* revalidate a dentry's inode attributes */
-int cifs_revalidate_dentry(struct dentry *dentry)
+int cifs_revalidate_dentry(struct dentry *dentry,
+ bool want_extra_bits, bool force)
{
int rc;
struct inode *inode = d_inode(dentry);
- rc = cifs_revalidate_dentry_attr(dentry);
+ rc = cifs_revalidate_dentry_attr(dentry, want_extra_bits, force);
if (rc)
return rc;
@@ -1958,28 +1978,62 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
struct inode *inode = d_inode(dentry);
+ struct cifsInodeInfo *cifs_i = CIFS_I(inode);
+ bool force = stat->query_flags & AT_FORCE_ATTR_SYNC;
+ bool want_extra_bits = false;
+ u32 info, ioc = 0;
+ u32 attrs;
int rc;
- /*
- * We need to be sure that all dirty pages are written and the server
- * has actual ctime, mtime and file length.
- */
- if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping &&
- inode->i_mapping->nrpages != 0) {
- rc = filemap_fdatawait(inode->i_mapping);
- if (rc) {
- mapping_set_error(inode->i_mapping, rc);
- return rc;
+ if (cifs_i->uid_faked)
+ stat->request_mask &= ~STATX_UID;
+ if (cifs_i->gid_faked)
+ stat->request_mask &= ~STATX_GID;
+
+ if ((stat->request_mask & STATX_BTIME && !cifs_i->btime_valid) ||
+ stat->request_mask & STATX_IOC_FLAGS)
+ want_extra_bits = force = true;
+
+ if (!(stat->query_flags & AT_NO_ATTR_SYNC)) {
+ /* Unless we're explicitly told not to sync, we need to be sure
+ * that all dirty pages are written and the server has actual
+ * ctime, mtime and file length.
+ */
+ bool flush = force;
+
+ if (stat->request_mask &
+ (STATX_CTIME | STATX_MTIME | STATX_SIZE))
+ flush = true;
+
+ if (flush &&
+ !CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping &&
+ inode->i_mapping->nrpages != 0) {
+ rc = filemap_fdatawait(inode->i_mapping);
+ if (rc) {
+ mapping_set_error(inode->i_mapping, rc);
+ return rc;
+ }
}
- }
- rc = cifs_revalidate_dentry_attr(dentry);
- if (rc)
- return rc;
+ rc = cifs_revalidate_dentry(dentry, want_extra_bits, force);
+ if (rc)
+ return rc;
+ }
generic_fillattr(inode, stat);
stat->blksize = CIFS_MAX_MSGSIZE;
- stat->ino = CIFS_I(inode)->uniqueid;
+
+ info = STATX_INFO_REMOTE | STATX_INFO_NONSYSTEM_OWNERSHIP;
+
+ if (cifs_i->btime_valid) {
+ stat->btime = cifs_i->btime;
+ stat->result_mask |= STATX_BTIME;
+ }
+
+ /* We don't promise an inode number if we made one up */
+ stat->ino = cifs_i->uniqueid;
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
+ stat->result_mask &= ~STATX_INO;
/*
* If on a multiuser mount without unix extensions or cifsacl being
@@ -1993,8 +2047,24 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
stat->uid = current_fsuid();
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
stat->gid = current_fsgid();
+ stat->result_mask &= ~(STATX_UID | STATX_GID);
}
- return rc;
+
+ attrs = cifs_i->cifsAttrs;
+ if (attrs & ATTR_TEMPORARY) info |= STATX_INFO_TEMPORARY;
+ if (attrs & ATTR_REPARSE) info |= STATX_INFO_REPARSE_POINT;
+ if (attrs & ATTR_OFFLINE) info |= STATX_INFO_OFFLINE;
+ if (attrs & ATTR_ENCRYPTED) info |= STATX_INFO_ENCRYPTED;
+ stat->information |= info;
+
+ if (attrs & ATTR_READONLY) ioc |= FS_IMMUTABLE_FL;
+ if (attrs & ATTR_COMPRESSED) ioc |= FS_COMPR_FL;
+ if (attrs & ATTR_HIDDEN) ioc |= FS_HIDDEN_FL;
+ if (attrs & ATTR_SYSTEM) ioc |= FS_SYSTEM_FL;
+ if (attrs & ATTR_ARCHIVE) ioc |= FS_ARCHIVE_FL;
+ stat->ioc_flags |= ioc;
+
+ return 0;
}
static int cifs_truncate_page(struct address_space *mapping, loff_t from)
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Steve French <smfrench@gmail.com> |
|---|---|
| Date | 2015-11-24 18:40 +0100 |
| Subject | Re: [PATCH 07/12] statx: CIFS: Return enhanced attributes |
| Message-ID | <qypJp-2KZ-39@gated-at.bofh.it> |
| In reply to | #1274147 |
Is it worth storing the same creation time twice (in slightly
different formats, struct timespec and u64 DCE time) in cifsInodeInfo?
On Fri, Nov 20, 2015 at 8:55 AM, David Howells <dhowells@redhat.com> wrote:
> Return enhanced attributes from the CIFS filesystem. This includes the
> following:
>
> (1) Return the file creation time as btime. We assume that the creation
> time won't change over the life of the inode.
>
> (2) Set STATX_INFO_AUTOMOUNT on referral/submount directories.
>
> (3) Unset STATX_INO if we made up the inode number and didn't get it from
> the server.
>
> (4) Unset STATX_[UG]ID if we are either returning values passed to mount
> and/or the server doesn't return them.
>
> (5) Set STATX_IOC_FLAGS and map various Windows file attributes to
> FS_xxx_FL flags in st_ioc_flags, fetching them from the server if we
> don't have them yet or don't have a current copy. This includes the
> following:
>
> ATTR_READONLY -> FS_IMMUTABLE_FL
> ATTR_COMPRESSED -> FS_COMPR_FL
> ATTR_HIDDEN -> FS_HIDDEN_FL
> ATTR_SYSTEM -> FS_SYSTEM_FL
> ATTR_ARCHIVE -> FS_ARCHIVE_FL
>
> (6) Set certain STATX_INFO_xxx to reflect other Windows file attributes:
>
> ATTR_TEMPORARY -> STATX_INFO_TEMPORARY;
> ATTR_REPARSE -> STATX_INFO_REPARSE_POINT;
> ATTR_OFFLINE -> STATX_INFO_OFFLINE;
> ATTR_ENCRYPTED -> STATX_INFO_ENCRYPTED;
>
> (7) Set STATX_INFO_REMOTE on all files fetched by CIFS.
>
> (8) Set STATX_INFO_NONSYSTEM_OWNERSHIP on all files as they all have
> Windows ownership details too.
>
> Furthermore, what cifs_getattr() does can be controlled as follows:
>
> (1) If AT_NO_ATTR_SYNC is indicated then this will suppress the flushing
> of outstanding writes and the rereading of the inode's attributes with
> the server as detailed below.
>
> (2) Otherwise:
>
> (a) If AT_FORCE_ATTR_SYNC is indicated, or mtime, ctime or size are
> requested then the outstanding writes will be written to the
> server first.
>
> (b) The inode's attributes will be reread from the server:
>
> (i) if AT_FORCE_ATTR_SYNC is indicated;
>
> (ii) if the cached attributes have expired;
>
> (iii) extra attributes are requested that aren't normally stored.
>
> If the inode isn't synchronised, then the cached attributes will be used -
> even if expired - without reference to the server. Some attributes may be
> unavailable that would otherwise be provided.
>
> Note that cifs_revalidate_dentry() will issue an extra operation to get the
> FILE_ALL_INFO in addition to the FILE_UNIX_BASIC_INFO if it needs to
> collect creation time and attributes on behalf of cifs_getattr().
>
> [NOTE: THIS PATCH IS UNTESTED!]
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
>
> fs/cifs/cifsfs.h | 4 +-
> fs/cifs/cifsglob.h | 8 +++
> fs/cifs/dir.c | 2 -
> fs/cifs/inode.c | 124 +++++++++++++++++++++++++++++++++++++++++-----------
> 4 files changed, 108 insertions(+), 30 deletions(-)
>
> diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
> index c3cc1609025f..fb38d47d84de 100644
> --- a/fs/cifs/cifsfs.h
> +++ b/fs/cifs/cifsfs.h
> @@ -71,9 +71,9 @@ extern int cifs_rmdir(struct inode *, struct dentry *);
> extern int cifs_rename2(struct inode *, struct dentry *, struct inode *,
> struct dentry *, unsigned int);
> extern int cifs_revalidate_file_attr(struct file *filp);
> -extern int cifs_revalidate_dentry_attr(struct dentry *);
> +extern int cifs_revalidate_dentry_attr(struct dentry *, bool, bool);
> extern int cifs_revalidate_file(struct file *filp);
> -extern int cifs_revalidate_dentry(struct dentry *);
> +extern int cifs_revalidate_dentry(struct dentry *, bool, bool);
> extern int cifs_invalidate_mapping(struct inode *inode);
> extern int cifs_revalidate_mapping(struct inode *inode);
> extern int cifs_zap_mapping(struct inode *inode);
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index b406a32deb1f..493e40a15b86 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -1152,7 +1152,11 @@ struct cifsInodeInfo {
> unsigned long flags;
> spinlock_t writers_lock;
> unsigned int writers; /* Number of writers on this inode */
> + bool btime_valid:1; /* stored creation time is valid */
> + bool uid_faked:1; /* true if i_uid is faked */
> + bool gid_faked:1; /* true if i_gid is faked */
> unsigned long time; /* jiffies of last update of inode */
> + struct timespec btime; /* creation time */
> u64 server_eof; /* current file size on server -- protected by i_lock */
> u64 uniqueid; /* server inode number */
> u64 createtime; /* creation time on server */
> @@ -1365,6 +1369,9 @@ struct dfs_info3_param {
> #define CIFS_FATTR_NEED_REVAL 0x4
> #define CIFS_FATTR_INO_COLLISION 0x8
> #define CIFS_FATTR_UNKNOWN_NLINK 0x10
> +#define CIFS_FATTR_WINATTRS_VALID 0x20 /* T if cf_btime and cf_cifsattrs valid */
> +#define CIFS_FATTR_UID_FAKED 0x40 /* T if cf_uid is faked */
> +#define CIFS_FATTR_GID_FAKED 0x80 /* T if cf_gid is faked */
>
> struct cifs_fattr {
> u32 cf_flags;
> @@ -1382,6 +1389,7 @@ struct cifs_fattr {
> struct timespec cf_atime;
> struct timespec cf_mtime;
> struct timespec cf_ctime;
> + struct timespec cf_btime;
> };
>
> static inline void free_dfs_info_param(struct dfs_info3_param *param)
> diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
> index c3eb998a99bd..4984f04b0677 100644
> --- a/fs/cifs/dir.c
> +++ b/fs/cifs/dir.c
> @@ -792,7 +792,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
> return -ECHILD;
>
> if (d_really_is_positive(direntry)) {
> - if (cifs_revalidate_dentry(direntry))
> + if (cifs_revalidate_dentry(direntry, false, false))
> return 0;
> else {
> /*
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index 6b66dd5d1540..fcb024efbd4b 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -166,13 +166,21 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
> cifs_nlink_fattr_to_inode(inode, fattr);
> inode->i_uid = fattr->cf_uid;
> inode->i_gid = fattr->cf_gid;
> + if (fattr->cf_flags & CIFS_FATTR_UID_FAKED)
> + cifs_i->uid_faked = true;
> + if (fattr->cf_flags & CIFS_FATTR_GID_FAKED)
> + cifs_i->gid_faked = true;
>
> /* if dynperm is set, don't clobber existing mode */
> if (inode->i_state & I_NEW ||
> !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM))
> inode->i_mode = fattr->cf_mode;
>
> - cifs_i->cifsAttrs = fattr->cf_cifsattrs;
> + if (fattr->cf_flags & CIFS_FATTR_WINATTRS_VALID) {
> + cifs_i->cifsAttrs = fattr->cf_cifsattrs;
> + cifs_i->btime = fattr->cf_btime;
> + cifs_i->btime_valid = true;
> + }
>
> if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
> cifs_i->time = 0;
> @@ -284,18 +292,22 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
> u64 id = le64_to_cpu(info->Uid);
> if (id < ((uid_t)-1)) {
> kuid_t uid = make_kuid(&init_user_ns, id);
> - if (uid_valid(uid))
> + if (uid_valid(uid)) {
> fattr->cf_uid = uid;
> + fattr->cf_flags |= CIFS_FATTR_UID_FAKED;
> + }
> }
> }
> -
> +
> fattr->cf_gid = cifs_sb->mnt_gid;
> if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) {
> u64 id = le64_to_cpu(info->Gid);
> if (id < ((gid_t)-1)) {
> kgid_t gid = make_kgid(&init_user_ns, id);
> - if (gid_valid(gid))
> + if (gid_valid(gid)) {
> fattr->cf_gid = gid;
> + fattr->cf_flags |= CIFS_FATTR_GID_FAKED;
> + }
> }
> }
>
> @@ -324,7 +336,8 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
> fattr->cf_ctime = CURRENT_TIME;
> fattr->cf_mtime = CURRENT_TIME;
> fattr->cf_nlink = 2;
> - fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
> + fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL |
> + CIFS_FATTR_UID_FAKED | CIFS_FATTR_GID_FAKED;
> }
>
> static int
> @@ -590,6 +603,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
> struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
>
> memset(fattr, 0, sizeof(*fattr));
> + fattr->cf_flags = CIFS_FATTR_WINATTRS_VALID;
> fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
> if (info->DeletePending)
> fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING;
> @@ -601,6 +615,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
>
> fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime);
> fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime);
> + fattr->cf_btime = cifs_NTtimeToUnix(info->CreationTime);
>
> if (adjust_tz) {
> fattr->cf_ctime.tv_sec += tcon->ses->server->timeAdj;
> @@ -1887,7 +1902,8 @@ int cifs_revalidate_file_attr(struct file *filp)
> return rc;
> }
>
> -int cifs_revalidate_dentry_attr(struct dentry *dentry)
> +int cifs_revalidate_dentry_attr(struct dentry *dentry,
> + bool want_extra_bits, bool force)
> {
> unsigned int xid;
> int rc = 0;
> @@ -1898,7 +1914,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
> if (inode == NULL)
> return -ENOENT;
>
> - if (!cifs_inode_needs_reval(inode))
> + if (!force && !cifs_inode_needs_reval(inode))
> return rc;
>
> xid = get_xid();
> @@ -1915,9 +1931,12 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
> full_path, inode, inode->i_count.counter,
> dentry, dentry->d_time, jiffies);
>
> - if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
> + if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) {
> rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
> - else
> + if (rc != 0)
> + goto out;
> + }
> + if (!cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext || want_extra_bits)
> rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
> xid, NULL);
>
> @@ -1940,12 +1959,13 @@ int cifs_revalidate_file(struct file *filp)
> }
>
> /* revalidate a dentry's inode attributes */
> -int cifs_revalidate_dentry(struct dentry *dentry)
> +int cifs_revalidate_dentry(struct dentry *dentry,
> + bool want_extra_bits, bool force)
> {
> int rc;
> struct inode *inode = d_inode(dentry);
>
> - rc = cifs_revalidate_dentry_attr(dentry);
> + rc = cifs_revalidate_dentry_attr(dentry, want_extra_bits, force);
> if (rc)
> return rc;
>
> @@ -1958,28 +1978,62 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
> struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
> struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
> struct inode *inode = d_inode(dentry);
> + struct cifsInodeInfo *cifs_i = CIFS_I(inode);
> + bool force = stat->query_flags & AT_FORCE_ATTR_SYNC;
> + bool want_extra_bits = false;
> + u32 info, ioc = 0;
> + u32 attrs;
> int rc;
>
> - /*
> - * We need to be sure that all dirty pages are written and the server
> - * has actual ctime, mtime and file length.
> - */
> - if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping &&
> - inode->i_mapping->nrpages != 0) {
> - rc = filemap_fdatawait(inode->i_mapping);
> - if (rc) {
> - mapping_set_error(inode->i_mapping, rc);
> - return rc;
> + if (cifs_i->uid_faked)
> + stat->request_mask &= ~STATX_UID;
> + if (cifs_i->gid_faked)
> + stat->request_mask &= ~STATX_GID;
> +
> + if ((stat->request_mask & STATX_BTIME && !cifs_i->btime_valid) ||
> + stat->request_mask & STATX_IOC_FLAGS)
> + want_extra_bits = force = true;
> +
> + if (!(stat->query_flags & AT_NO_ATTR_SYNC)) {
> + /* Unless we're explicitly told not to sync, we need to be sure
> + * that all dirty pages are written and the server has actual
> + * ctime, mtime and file length.
> + */
> + bool flush = force;
> +
> + if (stat->request_mask &
> + (STATX_CTIME | STATX_MTIME | STATX_SIZE))
> + flush = true;
> +
> + if (flush &&
> + !CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping &&
> + inode->i_mapping->nrpages != 0) {
> + rc = filemap_fdatawait(inode->i_mapping);
> + if (rc) {
> + mapping_set_error(inode->i_mapping, rc);
> + return rc;
> + }
> }
> - }
>
> - rc = cifs_revalidate_dentry_attr(dentry);
> - if (rc)
> - return rc;
> + rc = cifs_revalidate_dentry(dentry, want_extra_bits, force);
> + if (rc)
> + return rc;
> + }
>
> generic_fillattr(inode, stat);
> stat->blksize = CIFS_MAX_MSGSIZE;
> - stat->ino = CIFS_I(inode)->uniqueid;
> +
> + info = STATX_INFO_REMOTE | STATX_INFO_NONSYSTEM_OWNERSHIP;
> +
> + if (cifs_i->btime_valid) {
> + stat->btime = cifs_i->btime;
> + stat->result_mask |= STATX_BTIME;
> + }
> +
> + /* We don't promise an inode number if we made one up */
> + stat->ino = cifs_i->uniqueid;
> + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
> + stat->result_mask &= ~STATX_INO;
>
> /*
> * If on a multiuser mount without unix extensions or cifsacl being
> @@ -1993,8 +2047,24 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
> stat->uid = current_fsuid();
> if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
> stat->gid = current_fsgid();
> + stat->result_mask &= ~(STATX_UID | STATX_GID);
> }
> - return rc;
> +
> + attrs = cifs_i->cifsAttrs;
> + if (attrs & ATTR_TEMPORARY) info |= STATX_INFO_TEMPORARY;
> + if (attrs & ATTR_REPARSE) info |= STATX_INFO_REPARSE_POINT;
> + if (attrs & ATTR_OFFLINE) info |= STATX_INFO_OFFLINE;
> + if (attrs & ATTR_ENCRYPTED) info |= STATX_INFO_ENCRYPTED;
> + stat->information |= info;
> +
> + if (attrs & ATTR_READONLY) ioc |= FS_IMMUTABLE_FL;
> + if (attrs & ATTR_COMPRESSED) ioc |= FS_COMPR_FL;
> + if (attrs & ATTR_HIDDEN) ioc |= FS_HIDDEN_FL;
> + if (attrs & ATTR_SYSTEM) ioc |= FS_SYSTEM_FL;
> + if (attrs & ATTR_ARCHIVE) ioc |= FS_ARCHIVE_FL;
> + stat->ioc_flags |= ioc;
> +
> + return 0;
> }
>
> static int cifs_truncate_page(struct address_space *mapping, loff_t from)
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Thanks,
Steve
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2015-11-20 16:00 +0100 |
| Subject | [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding |
| Message-ID | <qwVkn-6h-47@gated-at.bofh.it> |
| In reply to | #1274142 |
The handling of extended timestamps in Ext4 is broken as can be seen in the
output of the test program attached below:
time extra bad decode good decode bad encode good encode
======== ===== ================= ================= =========== ===========
ffffffff 0 > ffffffffffffffff ffffffffffffffff > *ffffffff 3 ffffffff 0
80000000 0 > ffffffff80000000 ffffffff80000000 > *80000000 3 80000000 0
00000000 0 > 0 0 > 00000000 0 00000000 0
7fffffff 0 > 7fffffff 7fffffff > 7fffffff 0 7fffffff 0
80000000 1 > *ffffffff80000000 80000000 > *80000000 0 80000000 1
ffffffff 1 > *ffffffffffffffff ffffffff > *ffffffff 0 ffffffff 1
00000000 1 > 100000000 100000000 > 00000000 1 00000000 1
7fffffff 1 > 17fffffff 17fffffff > 7fffffff 1 7fffffff 1
80000000 2 > *ffffffff80000000 180000000 > *80000000 1 80000000 2
ffffffff 2 > *ffffffffffffffff 1ffffffff > *ffffffff 1 ffffffff 2
00000000 2 > 200000000 200000000 > 00000000 2 00000000 2
7fffffff 2 > 27fffffff 27fffffff > 7fffffff 2 7fffffff 2
80000000 3 > *ffffffff80000000 280000000 > *80000000 2 80000000 3
ffffffff 3 > *ffffffffffffffff 2ffffffff > *ffffffff 2 ffffffff 3
00000000 3 > 300000000 300000000 > 00000000 3 00000000 3
7fffffff 3 > 37fffffff 37fffffff > 7fffffff 3 7fffffff 3
The values marked with asterisks are wrong.
The problem is that with a 64-bit time, in ext4_decode_extra_time() the
epoch value is just OR'd with the sign-extended time - which, if negative,
has all of the upper 32 bits set anyway. We need to add the epoch instead
of OR'ing it. In ext4_encode_extra_time(), the reverse operation needs to
take place as the 32-bit part of the number of seconds needs to be
subtracted from the 64-bit value before the epoch is shifted down.
Since the epoch is presumably unsigned, this has the slightly strange
effect of, for epochs > 0, putting the 0x80000000-0xffffffff range before
the 0x00000000-0x7fffffff range.
This affects all kernels from v2.6.23-rc1 onwards.
The test program:
#include <stdio.h>
#define EXT4_FITS_IN_INODE(x, y, z) 1
#define EXT4_EPOCH_BITS 2
#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
#define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS)
#define le32_to_cpu(x) (x)
#define cpu_to_le32(x) (x)
typedef unsigned int __le32;
typedef unsigned int u32;
typedef signed int s32;
typedef unsigned long long __u64;
typedef signed long long s64;
struct timespec {
long long tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
struct ext4_inode_info {
struct timespec i_crtime;
};
struct ext4_inode {
__le32 i_crtime; /* File Creation time */
__le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
};
/* Incorrect implementation */
static inline void ext4_decode_extra_time_bad(struct timespec *time, __le32 extra)
{
if (sizeof(time->tv_sec) > 4)
time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
<< 32;
time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
}
static inline __le32 ext4_encode_extra_time_bad(struct timespec *time)
{
return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
(time->tv_sec >> 32) & EXT4_EPOCH_MASK : 0) |
((time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK));
}
/* Fixed implementation */
static inline void ext4_decode_extra_time_good(struct timespec *time, __le32 _extra)
{
u32 extra = le32_to_cpu(_extra);
u32 epoch = extra & EXT4_EPOCH_MASK;
time->tv_sec = (s32)time->tv_sec + ((s64)epoch << 32);
time->tv_nsec = (extra & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
}
static inline __le32 ext4_encode_extra_time_good(struct timespec *time)
{
u32 extra;
s64 epoch = time->tv_sec - (s32)time->tv_sec;
extra = (epoch >> 32) & EXT4_EPOCH_MASK;
extra |= (time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK;
return cpu_to_le32(extra);
}
#define EXT4_INODE_GET_XTIME_BAD(xtime, inode, raw_inode) \
do { \
(inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime); \
if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \
ext4_decode_extra_time_bad(&(inode)->xtime, \
raw_inode->xtime ## _extra); \
else \
(inode)->xtime.tv_nsec = 0; \
} while (0)
#define EXT4_INODE_SET_XTIME_BAD(xtime, inode, raw_inode) \
do { \
(raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec); \
if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \
(raw_inode)->xtime ## _extra = \
ext4_encode_extra_time_bad(&(inode)->xtime); \
} while (0)
#define EXT4_INODE_GET_XTIME_GOOD(xtime, inode, raw_inode) \
do { \
(inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime); \
if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \
ext4_decode_extra_time_good(&(inode)->xtime, \
raw_inode->xtime ## _extra); \
else \
(inode)->xtime.tv_nsec = 0; \
} while (0)
#define EXT4_INODE_SET_XTIME_GOOD(xtime, inode, raw_inode) \
do { \
(raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec); \
if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \
(raw_inode)->xtime ## _extra = \
ext4_encode_extra_time_good(&(inode)->xtime); \
} while (0)
static const struct test {
unsigned crtime;
unsigned extra;
long long sec;
int nsec;
} tests[] = {
// crtime extra tv_sec tv_nsec
0xffffffff, 0x00000000, 0xffffffffffffffff, 0,
0x80000000, 0x00000000, 0xffffffff80000000, 0,
0x00000000, 0x00000000, 0x0000000000000000, 0,
0x7fffffff, 0x00000000, 0x000000007fffffff, 0,
0x80000000, 0x00000001, 0x0000000080000000, 0,
0xffffffff, 0x00000001, 0x00000000ffffffff, 0,
0x00000000, 0x00000001, 0x0000000100000000, 0,
0x7fffffff, 0x00000001, 0x000000017fffffff, 0,
0x80000000, 0x00000002, 0x0000000180000000, 0,
0xffffffff, 0x00000002, 0x00000001ffffffff, 0,
0x00000000, 0x00000002, 0x0000000200000000, 0,
0x7fffffff, 0x00000002, 0x000000027fffffff, 0,
0x80000000, 0x00000003, 0x0000000280000000, 0,
0xffffffff, 0x00000003, 0x00000002ffffffff, 0,
0x00000000, 0x00000003, 0x0000000300000000, 0,
0x7fffffff, 0x00000003, 0x000000037fffffff, 0,
};
int main()
{
struct ext4_inode_info ii_bad, ii_good;
struct ext4_inode raw, *praw = &raw;
struct ext4_inode raw_bad, *praw_bad = &raw_bad;
struct ext4_inode raw_good, *praw_good = &raw_good;
const struct test *t;
int i, ret = 0;
printf("time extra bad decode good decode bad encode good encode\n");
printf("======== ===== ================= ================= =========== ===========\n");
for (i = 0; i < sizeof(tests) / sizeof(t[0]); i++) {
t = &tests[i];
raw.i_crtime = t->crtime;
raw.i_crtime_extra = t->extra;
printf("%08x %5d > ", t->crtime, t->extra);
EXT4_INODE_GET_XTIME_BAD(i_crtime, &ii_bad, praw);
EXT4_INODE_GET_XTIME_GOOD(i_crtime, &ii_good, praw);
if (ii_bad.i_crtime.tv_sec != t->sec ||
ii_bad.i_crtime.tv_nsec != t->nsec)
printf("*");
else
printf(" ");
printf("%16llx", ii_bad.i_crtime.tv_sec);
printf(" ");
if (ii_good.i_crtime.tv_sec != t->sec ||
ii_good.i_crtime.tv_nsec != t->nsec) {
printf("*");
ret = 1;
} else {
printf(" ");
}
printf("%16llx", ii_good.i_crtime.tv_sec);
EXT4_INODE_SET_XTIME_BAD(i_crtime, &ii_good, praw_bad);
EXT4_INODE_SET_XTIME_GOOD(i_crtime, &ii_good, praw_good);
printf(" > ");
if (raw_bad.i_crtime != raw.i_crtime ||
raw_bad.i_crtime_extra != raw.i_crtime_extra)
printf("*");
else
printf(" ");
printf("%08llx %d", raw_bad.i_crtime, raw_bad.i_crtime_extra);
printf(" ");
if (raw_good.i_crtime != raw.i_crtime ||
raw_good.i_crtime_extra != raw.i_crtime_extra) {
printf("*");
ret = 1;
} else {
printf(" ");
}
printf("%08llx %d", raw_good.i_crtime, raw_good.i_crtime_extra);
printf("\n");
}
return ret;
}
Signed-off-by: David Howells <dhowells@redhat.com>
---
fs/ext4/ext4.h | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index fd1f28be5296..31efcd78bf51 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -723,19 +723,23 @@ struct move_extent {
<= (EXT4_GOOD_OLD_INODE_SIZE + \
(einode)->i_extra_isize)) \
-static inline __le32 ext4_encode_extra_time(struct timespec *time)
+static inline void ext4_decode_extra_time(struct timespec *time, __le32 _extra)
{
- return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
- (time->tv_sec >> 32) & EXT4_EPOCH_MASK : 0) |
- ((time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK));
+ u32 extra = le32_to_cpu(_extra);
+ u32 epoch = extra & EXT4_EPOCH_MASK;
+
+ time->tv_sec = (s32)time->tv_sec + ((s64)epoch << 32);
+ time->tv_nsec = (extra & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
}
-static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
+static inline __le32 ext4_encode_extra_time(struct timespec *time)
{
- if (sizeof(time->tv_sec) > 4)
- time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
- << 32;
- time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
+ u32 extra;
+ s64 epoch = time->tv_sec - (s32)time->tv_sec;
+
+ extra = (epoch >> 32) & EXT4_EPOCH_MASK;
+ extra |= (time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK;
+ return cpu_to_le32(extra);
}
#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode) \
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Dilger <adilger@dilger.ca> |
|---|---|
| Date | 2015-11-24 18:40 +0100 |
| Subject | Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding |
| Message-ID | <qypJo-2KZ-31@gated-at.bofh.it> |
| In reply to | #1274148 |
[Multipart message — attachments visible in raw view] — view raw
On Nov 20, 2015, at 7:54 AM, David Howells <dhowells@redhat.com> wrote:
>
> The handling of extended timestamps in Ext4 is broken as can be seen in the
> output of the test program attached below:
>
> time extra bad decode good decode bad encode good encode
> ======== ===== ================= ================= =========== ===========
> ffffffff 0 > ffffffffffffffff ffffffffffffffff > *ffffffff 3 ffffffff 0
> 80000000 0 > ffffffff80000000 ffffffff80000000 > *80000000 3 80000000 0
> 00000000 0 > 0 0 > 00000000 0 00000000 0
> 7fffffff 0 > 7fffffff 7fffffff > 7fffffff 0 7fffffff 0
> 80000000 1 > *ffffffff80000000 80000000 > *80000000 0 80000000 1
> ffffffff 1 > *ffffffffffffffff ffffffff > *ffffffff 0 ffffffff 1
> 00000000 1 > 100000000 100000000 > 00000000 1 00000000 1
> 7fffffff 1 > 17fffffff 17fffffff > 7fffffff 1 7fffffff 1
> 80000000 2 > *ffffffff80000000 180000000 > *80000000 1 80000000 2
> ffffffff 2 > *ffffffffffffffff 1ffffffff > *ffffffff 1 ffffffff 2
> 00000000 2 > 200000000 200000000 > 00000000 2 00000000 2
> 7fffffff 2 > 27fffffff 27fffffff > 7fffffff 2 7fffffff 2
> 80000000 3 > *ffffffff80000000 280000000 > *80000000 2 80000000 3
> ffffffff 3 > *ffffffffffffffff 2ffffffff > *ffffffff 2 ffffffff 3
> 00000000 3 > 300000000 300000000 > 00000000 3 00000000 3
> 7fffffff 3 > 37fffffff 37fffffff > 7fffffff 3 7fffffff 3
>
> The values marked with asterisks are wrong.
>
> The problem is that with a 64-bit time, in ext4_decode_extra_time() the
> epoch value is just OR'd with the sign-extended time - which, if negative,
> has all of the upper 32 bits set anyway. We need to add the epoch instead
> of OR'ing it. In ext4_encode_extra_time(), the reverse operation needs to
> take place as the 32-bit part of the number of seconds needs to be
> subtracted from the 64-bit value before the epoch is shifted down.
>
> Since the epoch is presumably unsigned, this has the slightly strange
> effect of, for epochs > 0, putting the 0x80000000-0xffffffff range before
> the 0x00000000-0x7fffffff range.
>
> This affects all kernels from v2.6.23-rc1 onwards.
>
> The test program:
>
> #include <stdio.h>
>
> #define EXT4_FITS_IN_INODE(x, y, z) 1
> #define EXT4_EPOCH_BITS 2
> #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
> #define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS)
>
> #define le32_to_cpu(x) (x)
> #define cpu_to_le32(x) (x)
> typedef unsigned int __le32;
> typedef unsigned int u32;
> typedef signed int s32;
> typedef unsigned long long __u64;
> typedef signed long long s64;
>
> struct timespec {
> long long tv_sec; /* seconds */
> long tv_nsec; /* nanoseconds */
> };
>
> struct ext4_inode_info {
> struct timespec i_crtime;
> };
>
> struct ext4_inode {
> __le32 i_crtime; /* File Creation time */
> __le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
> };
>
> /* Incorrect implementation */
> static inline void ext4_decode_extra_time_bad(struct timespec *time, __le32 extra)
> {
> if (sizeof(time->tv_sec) > 4)
> time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
> << 32;
> time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
> }
>
> static inline __le32 ext4_encode_extra_time_bad(struct timespec *time)
> {
> return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
> (time->tv_sec >> 32) & EXT4_EPOCH_MASK : 0) |
> ((time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK));
> }
>
> /* Fixed implementation */
> static inline void ext4_decode_extra_time_good(struct timespec *time, __le32 _extra)
> {
> u32 extra = le32_to_cpu(_extra);
> u32 epoch = extra & EXT4_EPOCH_MASK;
>
> time->tv_sec = (s32)time->tv_sec + ((s64)epoch << 32);
> time->tv_nsec = (extra & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
> }
>
> static inline __le32 ext4_encode_extra_time_good(struct timespec *time)
> {
> u32 extra;
> s64 epoch = time->tv_sec - (s32)time->tv_sec;
>
> extra = (epoch >> 32) & EXT4_EPOCH_MASK;
> extra |= (time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK;
> return cpu_to_le32(extra);
> }
>
> #define EXT4_INODE_GET_XTIME_BAD(xtime, inode, raw_inode) \
> do { \
> (inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime); \
> if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \
> ext4_decode_extra_time_bad(&(inode)->xtime, \
> raw_inode->xtime ## _extra); \
> else \
> (inode)->xtime.tv_nsec = 0; \
> } while (0)
>
> #define EXT4_INODE_SET_XTIME_BAD(xtime, inode, raw_inode) \
> do { \
> (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec); \
> if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \
> (raw_inode)->xtime ## _extra = \
> ext4_encode_extra_time_bad(&(inode)->xtime); \
> } while (0)
>
> #define EXT4_INODE_GET_XTIME_GOOD(xtime, inode, raw_inode) \
> do { \
> (inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime); \
> if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \
> ext4_decode_extra_time_good(&(inode)->xtime, \
> raw_inode->xtime ## _extra); \
> else \
> (inode)->xtime.tv_nsec = 0; \
> } while (0)
>
> #define EXT4_INODE_SET_XTIME_GOOD(xtime, inode, raw_inode) \
> do { \
> (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec); \
> if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \
> (raw_inode)->xtime ## _extra = \
> ext4_encode_extra_time_good(&(inode)->xtime); \
> } while (0)
>
> static const struct test {
> unsigned crtime;
> unsigned extra;
> long long sec;
> int nsec;
> } tests[] = {
> // crtime extra tv_sec tv_nsec
> 0xffffffff, 0x00000000, 0xffffffffffffffff, 0,
> 0x80000000, 0x00000000, 0xffffffff80000000, 0,
> 0x00000000, 0x00000000, 0x0000000000000000, 0,
> 0x7fffffff, 0x00000000, 0x000000007fffffff, 0,
> 0x80000000, 0x00000001, 0x0000000080000000, 0,
> 0xffffffff, 0x00000001, 0x00000000ffffffff, 0,
> 0x00000000, 0x00000001, 0x0000000100000000, 0,
> 0x7fffffff, 0x00000001, 0x000000017fffffff, 0,
> 0x80000000, 0x00000002, 0x0000000180000000, 0,
> 0xffffffff, 0x00000002, 0x00000001ffffffff, 0,
> 0x00000000, 0x00000002, 0x0000000200000000, 0,
> 0x7fffffff, 0x00000002, 0x000000027fffffff, 0,
> 0x80000000, 0x00000003, 0x0000000280000000, 0,
> 0xffffffff, 0x00000003, 0x00000002ffffffff, 0,
> 0x00000000, 0x00000003, 0x0000000300000000, 0,
> 0x7fffffff, 0x00000003, 0x000000037fffffff, 0,
> };
>
> int main()
> {
> struct ext4_inode_info ii_bad, ii_good;
> struct ext4_inode raw, *praw = &raw;
> struct ext4_inode raw_bad, *praw_bad = &raw_bad;
> struct ext4_inode raw_good, *praw_good = &raw_good;
> const struct test *t;
> int i, ret = 0;
>
> printf("time extra bad decode good decode bad encode good encode\n");
> printf("======== ===== ================= ================= =========== ===========\n");
> for (i = 0; i < sizeof(tests) / sizeof(t[0]); i++) {
> t = &tests[i];
> raw.i_crtime = t->crtime;
> raw.i_crtime_extra = t->extra;
> printf("%08x %5d > ", t->crtime, t->extra);
>
> EXT4_INODE_GET_XTIME_BAD(i_crtime, &ii_bad, praw);
> EXT4_INODE_GET_XTIME_GOOD(i_crtime, &ii_good, praw);
> if (ii_bad.i_crtime.tv_sec != t->sec ||
> ii_bad.i_crtime.tv_nsec != t->nsec)
> printf("*");
> else
> printf(" ");
> printf("%16llx", ii_bad.i_crtime.tv_sec);
> printf(" ");
> if (ii_good.i_crtime.tv_sec != t->sec ||
> ii_good.i_crtime.tv_nsec != t->nsec) {
> printf("*");
> ret = 1;
> } else {
> printf(" ");
> }
> printf("%16llx", ii_good.i_crtime.tv_sec);
>
> EXT4_INODE_SET_XTIME_BAD(i_crtime, &ii_good, praw_bad);
> EXT4_INODE_SET_XTIME_GOOD(i_crtime, &ii_good, praw_good);
>
> printf(" > ");
> if (raw_bad.i_crtime != raw.i_crtime ||
> raw_bad.i_crtime_extra != raw.i_crtime_extra)
> printf("*");
> else
> printf(" ");
> printf("%08llx %d", raw_bad.i_crtime, raw_bad.i_crtime_extra);
> printf(" ");
>
> if (raw_good.i_crtime != raw.i_crtime ||
> raw_good.i_crtime_extra != raw.i_crtime_extra) {
> printf("*");
> ret = 1;
> } else {
> printf(" ");
> }
> printf("%08llx %d", raw_good.i_crtime, raw_good.i_crtime_extra);
> printf("\n");
> }
>
> return ret;
> }
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
>
> fs/ext4/ext4.h | 22 +++++++++++++---------
> 1 file changed, 13 insertions(+), 9 deletions(-)
>
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index fd1f28be5296..31efcd78bf51 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -723,19 +723,23 @@ struct move_extent {
> <= (EXT4_GOOD_OLD_INODE_SIZE + \
> (einode)->i_extra_isize)) \
>
> -static inline __le32 ext4_encode_extra_time(struct timespec *time)
> +static inline void ext4_decode_extra_time(struct timespec *time, __le32 _extra)
> {
> - return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
> - (time->tv_sec >> 32) & EXT4_EPOCH_MASK : 0) |
> - ((time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK));
> + u32 extra = le32_to_cpu(_extra);
> + u32 epoch = extra & EXT4_EPOCH_MASK;
> +
> + time->tv_sec = (s32)time->tv_sec + ((s64)epoch << 32);
Minor nit - two spaces before "<<".
> + time->tv_nsec = (extra & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
> }
>
> -static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
> +static inline __le32 ext4_encode_extra_time(struct timespec *time)
> {
> - if (sizeof(time->tv_sec) > 4)
> - time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
> - << 32;
> - time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
> + u32 extra;
> + s64 epoch = time->tv_sec - (s32)time->tv_sec;
> +
> + extra = (epoch >> 32) & EXT4_EPOCH_MASK;
> + extra |= (time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK;
> + return cpu_to_le32(extra);
> }
David, thanks for moving this patch forward.
It would have been easier to review if the order of encode and decode
functions had not been reversed... :-)
It would be good to get a comment block in the code describing the encoding:
/*
* We need is an encoding that preserves the times for extra epoch "00":
*
* extra add to 32-bit
* epoch tv_sec to get
* bits decoded 64-bit tv_sec 64-bit value valid time range
* 0 -0x80000000..-0x00000001 0x000000000 1901-12-13..1969-12-31
* 0 0x000000000..0x07fffffff 0x000000000 1970-01-01..2038-01-19
* 1 0x080000000..0x0ffffffff 0x100000000 2038-01-19..2106-02-07
* 1 0x100000000..0x17fffffff 0x100000000 2106-02-07..2174-02-25
* 2 0x180000000..0x1ffffffff 0x200000000 2174-02-25..2242-03-16
* 2 0x200000000..0x27fffffff 0x200000000 2242-03-16..2310-04-04
* 3 0x280000000..0x2ffffffff 0x300000000 2310-04-04..2378-04-22
* 3 0x300000000..0x37fffffff 0x300000000 2378-04-22..2446-05-10
*
* Note that previous versions of the kernel on 64-bit systems would
* incorrectly use extra epoch bits 1,1 for dates between 1901 and 1970.
* e2fsck will correct this, assuming that it is run on the affected
* filesystem before 2242.
*/
The only other question is whether you compile tested this on a 32-bit
system? IIRC, the "sizeof(time->tv_sec)" check was to avoid compiler
warnings due to assigning values too large for the data type, and (to
a lesser extent) avoiding overhead on those systems.
If there is no 32-bit compile warning then I'm fine with this as-is,
since systems with 32-bit tv_sec are going to be broken at that point
in any case.
Cheers, Andreas
[toc] | [prev] | [next] | [standalone]
| From | Theodore Ts'o <tytso@mit.edu> |
|---|---|
| Date | 2015-11-24 20:40 +0100 |
| Subject | Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding |
| Message-ID | <qyrBw-3WX-19@gated-at.bofh.it> |
| In reply to | #1274148 |
This is the patch I would prefer to use (and in fact which I have
added to the ext4 tree):
There are issues with 32-bit vs 64-bit encoding of times before
January 1, 1970, which are handled with this patch which is not
handled with what you have in your patch series. So I'd prefer if you
drop this patch, and I'll get this sent to Linus as a bug fix for 4.4.
Cheers,
- Ted
commit e0d738b05d484487b7e1e3c6d537da8bbef80c86
Author: David Turner <novalis@novalis.org>
Date: Tue Nov 24 14:34:37 2015 -0500
ext4: Fix handling of extended tv_sec
In ext4, the bottom two bits of {a,c,m}time_extra are used to extend
the {a,c,m}time fields, deferring the year 2038 problem to the year
2446.
When decoding these extended fields, for times whose bottom 32 bits
would represent a negative number, sign extension causes the 64-bit
extended timestamp to be negative as well, which is not what's
intended. This patch corrects that issue, so that the only negative
{a,c,m}times are those between 1901 and 1970 (as per 32-bit signed
timestamps).
Some older kernels might have written pre-1970 dates with 1,1 in the
extra bits. This patch treats those incorrectly-encoded dates as
pre-1970, instead of post-2311, until kernel 4.20 is released.
Hopefully by then e2fsck will have fixed up the bad data.
Also add a comment explaining the encoding of ext4's extra {a,c,m}time
bits.
Signed-off-by: David Turner <novalis@novalis.org>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reported-by: Mark Harris <mh8928@yahoo.com>
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=23732
Cc: stable@vger.kernel.org
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 750063f..fddce29 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -26,6 +26,7 @@
#include <linux/seqlock.h>
#include <linux/mutex.h>
#include <linux/timer.h>
+#include <linux/version.h>
#include <linux/wait.h>
#include <linux/blockgroup_lock.h>
#include <linux/percpu_counter.h>
@@ -727,19 +728,53 @@ struct move_extent {
<= (EXT4_GOOD_OLD_INODE_SIZE + \
(einode)->i_extra_isize)) \
+/*
+ * We use an encoding that preserves the times for extra epoch "00":
+ *
+ * extra msb of adjust for signed
+ * epoch 32-bit 32-bit tv_sec to
+ * bits time decoded 64-bit tv_sec 64-bit tv_sec valid time range
+ * 0 0 1 -0x80000000..-0x00000001 0x000000000 1901-12-13..1969-12-31
+ * 0 0 0 0x000000000..0x07fffffff 0x000000000 1970-01-01..2038-01-19
+ * 0 1 1 0x080000000..0x0ffffffff 0x100000000 2038-01-19..2106-02-07
+ * 0 1 0 0x100000000..0x17fffffff 0x100000000 2106-02-07..2174-02-25
+ * 1 0 1 0x180000000..0x1ffffffff 0x200000000 2174-02-25..2242-03-16
+ * 1 0 0 0x200000000..0x27fffffff 0x200000000 2242-03-16..2310-04-04
+ * 1 1 1 0x280000000..0x2ffffffff 0x300000000 2310-04-04..2378-04-22
+ * 1 1 0 0x300000000..0x37fffffff 0x300000000 2378-04-22..2446-05-10
+ *
+ * Note that previous versions of the kernel on 64-bit systems would
+ * incorrectly use extra epoch bits 1,1 for dates between 1901 and
+ * 1970. e2fsck will correct this, assuming that it is run on the
+ * affected filesystem before 2242.
+ */
+
static inline __le32 ext4_encode_extra_time(struct timespec *time)
{
- return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
- (time->tv_sec >> 32) & EXT4_EPOCH_MASK : 0) |
- ((time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK));
+ u32 extra = sizeof(time->tv_sec) > 4 ?
+ ((time->tv_sec - (s32)time->tv_sec) >> 32) & EXT4_EPOCH_MASK : 0;
+ return cpu_to_le32(extra | (time->tv_nsec << EXT4_EPOCH_BITS));
}
static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
{
- if (sizeof(time->tv_sec) > 4)
- time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
- << 32;
- time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
+ if (unlikely(sizeof(time->tv_sec) > 4 &&
+ (extra & cpu_to_le32(EXT4_EPOCH_MASK)))) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)
+ /* Handle legacy encoding of pre-1970 dates with epoch
+ * bits 1,1. We assume that by kernel version 4.20,
+ * everyone will have run fsck over the affected
+ * filesystems to correct the problem.
+ */
+ u64 extra_bits = le32_to_cpu(extra) & EXT4_EPOCH_MASK;
+ if (extra_bits == 3)
+ extra_bits = 0;
+ time->tv_sec += extra_bits << 32;
+#else
+ time->tv_sec += (u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) << 32;
+#endif
+ }
+ time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
}
#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode) \
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Arnd Bergmann <arnd@arndb.de> |
|---|---|
| Date | 2015-11-24 21:20 +0100 |
| Subject | Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding |
| Message-ID | <qysed-4rc-3@gated-at.bofh.it> |
| In reply to | #1276728 |
On Tuesday 24 November 2015 14:36:46 Theodore Ts'o wrote: > This is the patch I would prefer to use (and in fact which I have > added to the ext4 tree): > > There are issues with 32-bit vs 64-bit encoding of times before > January 1, 1970, which are handled with this patch which is not > handled with what you have in your patch series. So I'd prefer if you > drop this patch, and I'll get this sent to Linus as a bug fix for 4.4. I'm happy with either one. Apparently both Davids have arrived with almost the same algorithm and implementation, with the exception of the pre-1970 handling you mention there. Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Theodore Ts'o <tytso@mit.edu> |
|---|---|
| Date | 2015-11-29 03:50 +0100 |
| Subject | Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding |
| Message-ID | <qA0dP-kQ-3@gated-at.bofh.it> |
| In reply to | #1276739 |
On Tue, Nov 24, 2015 at 09:10:53PM +0100, Arnd Bergmann wrote: > On Tuesday 24 November 2015 14:36:46 Theodore Ts'o wrote: > > This is the patch I would prefer to use (and in fact which I have > > added to the ext4 tree): > > > > There are issues with 32-bit vs 64-bit encoding of times before > > January 1, 1970, which are handled with this patch which is not > > handled with what you have in your patch series. So I'd prefer if you > > drop this patch, and I'll get this sent to Linus as a bug fix for 4.4. > > I'm happy with either one. Apparently both Davids have arrived with > almost the same algorithm and implementation, with the exception of > the pre-1970 handling you mention there. I was doing some testing on x86, which leads me to ask --- what's the current thinking about post y2038 on 32-bit platforms such as x86? I see that there was some talk about using struct timespec64, but we haven't made the transition in the VFS interfaces yet, despite a comment in an LWN article from 2014 stating that "the first steps have been taken; hopefully the rest will follow before too long". Cheers, - Ted -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Arnd Bergmann <arnd@arndb.de> |
|---|---|
| Date | 2015-11-29 22:40 +0100 |
| Subject | Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding |
| Message-ID | <qAhRo-2Xn-27@gated-at.bofh.it> |
| In reply to | #1279259 |
On Saturday 28 November 2015 21:45:55 Theodore Ts'o wrote: > On Tue, Nov 24, 2015 at 09:10:53PM +0100, Arnd Bergmann wrote: > > On Tuesday 24 November 2015 14:36:46 Theodore Ts'o wrote: > > > This is the patch I would prefer to use (and in fact which I have > > > added to the ext4 tree): > > > > > > There are issues with 32-bit vs 64-bit encoding of times before > > > January 1, 1970, which are handled with this patch which is not > > > handled with what you have in your patch series. So I'd prefer if you > > > drop this patch, and I'll get this sent to Linus as a bug fix for 4.4. > > > > I'm happy with either one. Apparently both Davids have arrived with > > almost the same algorithm and implementation, with the exception of > > the pre-1970 handling you mention there. > > I was doing some testing on x86, which leads me to ask --- what's the > current thinking about post y2038 on 32-bit platforms such as x86? I > see that there was some talk about using struct timespec64, but we > haven't made the transition in the VFS interfaces yet, despite a > comment in an LWN article from 2014 stating that "the first steps have > been taken; hopefully the rest will follow before too long". The approach in my initial VFS series was to introduce 'struct inode_time', but I have basically abandoned that idea now, after we decided to introduce 'timespec64' inside of the kernel and use that for other subsystems. The rought plan is now to have separate time64_t and u32 seconds/nanoseconds values in 'struct inode', 'struct iattr' and 'struct kstat' and use inline functions or macros to extract or set them as time64_t or timespec64 in file system code, but that code is not written yet. I'm mostly coordinating the y2038 work at the moment, but that means that a lot of the work is going into individual drivers that a single person can easily handle. We've had a couple of people who tried looking at VFS, but none of them followed through, so it got delayed a bit. However, Deepa Dinamani is now looking y2038 for VFS and individual file systems as part of her Outreachy internship and I'm optimistic that we'll soon be making progress again here with her work. The other large missing piece is the system call implementation. I have posted a series earlier this year before my parental leave, and it's currently lacking review from libc folks, and blocked on me to update the series and post it again. Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Theodore Ts'o <tytso@mit.edu> |
|---|---|
| Date | 2015-11-30 15:20 +0100 |
| Subject | Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding |
| Message-ID | <qAxt8-4HX-13@gated-at.bofh.it> |
| In reply to | #1279426 |
On Sun, Nov 29, 2015 at 10:30:39PM +0100, Arnd Bergmann wrote: > The other large missing piece is the system call implementation. I have > posted a series earlier this year before my parental leave, and it's > currently lacking review from libc folks, and blocked on me to update > the series and post it again. I assume that this also means there hasn't been much thought about userspace support above libc? i.e., how to take a 64-bit time64_t (or changing the size of time_t) and translating that to a string using some kind of version of ctime() and asctime(), and how to parse a post-2038 date string and turning it into a 64-bit time_t on a 32-bit platform? The reason why I'm asking is because I'm thinking about how to add the appropriate regression test support to e2fsprogs for 32-bit platforms. I'm probably going to just skip the tests on architectures where sizeof(time_t) == 4 for now, since with a 32-bit time_t adding support for post-2038 in a e2fsprogs-specific way is (a) something I don't have time for, and (b) probably a waste of time since presumably we will either need to have a more general solution, or simply decide to give up on 32-bit platforms by 2038.... Cheers, - Ted -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Arnd Bergmann <arnd@arndb.de> |
|---|---|
| Date | 2015-11-30 15:40 +0100 |
| Subject | Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding |
| Message-ID | <qAxMu-4Or-25@gated-at.bofh.it> |
| In reply to | #1279904 |
On Monday 30 November 2015 09:16:05 Theodore Ts'o wrote: > On Sun, Nov 29, 2015 at 10:30:39PM +0100, Arnd Bergmann wrote: > > The other large missing piece is the system call implementation. I have > > posted a series earlier this year before my parental leave, and it's > > currently lacking review from libc folks, and blocked on me to update > > the series and post it again. > > I assume that this also means there hasn't been much thought about > userspace support above libc? i.e., how to take a 64-bit time64_t (or > changing the size of time_t) and translating that to a string using > some kind of version of ctime() and asctime(), and how to parse a > post-2038 date string and turning it into a 64-bit time_t on a 32-bit > platform? > > The reason why I'm asking is because I'm thinking about how to add the > appropriate regression test support to e2fsprogs for 32-bit platforms. > I'm probably going to just skip the tests on architectures where > sizeof(time_t) == 4 for now, since with a 32-bit time_t adding support > for post-2038 in a e2fsprogs-specific way is (a) something I don't > have time for, and (b) probably a waste of time since presumably we > will either need to have a more general solution, or simply decide to > give up on 32-bit platforms by 2038.... We are definitely going to be using 32-bit embedded platforms in 2038, but we won't be using a 32-bit time_t then, so basing the check on sizeof(time_t) sounds reasonable. I assume most generic distros will stay with 32-bit time_t for compatibility reasons and just not give long term support for 32-bit architectures, while the embedded distros will move over to 64-bit time_t, but on those you recompile all user space for each product anyway. The glibc functions should all work with a 64-bit time_t as they do today on 64-bit architectures. There is an open discussion on how you move to 64-bit time_t. With the current glibc plan at https://sourceware.org/glibc/wiki/Y2038ProofnessDesign, you will have to set -D_TIME_BITS=64 to enable it explicitly, but I'd also like to see a way to build a glibc that defaults to that and does not allow backwards compatibility, which is important for folks that want to ship a system that has they can guarantee to survive 2038. Arnd -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Elmar Stellnberger <estellnb@elstel.org> |
|---|---|
| Date | 2015-11-30 16:00 +0100 |
| Subject | Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding |
| Message-ID | <qAy5P-4Vq-3@gated-at.bofh.it> |
| In reply to | #1279904 |
On 30.11.2015 15:16, Theodore Ts'o wrote: > On Sun, Nov 29, 2015 at 10:30:39PM +0100, Arnd Bergmann wrote: >> The other large missing piece is the system call implementation. I have >> posted a series earlier this year before my parental leave, and it's >> currently lacking review from libc folks, and blocked on me to update >> the series and post it again. > > I assume that this also means there hasn't been much thought about > userspace support above libc? i.e., how to take a 64-bit time64_t (or > changing the size of time_t) and translating that to a string using > some kind of version of ctime() and asctime(), and how to parse a > post-2038 date string and turning it into a 64-bit time_t on a 32-bit > platform? > Arnd, I would just like to tell you how much I welcome your decision for a new __kernel_time64_t! As a time[64]_t is basically well defined counting artificial seconds since the epoch (1970-01-01 00:00) where every year divisible by four is a leap year that is for the meanwhile already sufficient to make use of your new type. I just think about the Mayan calendar application which I have implemented last year (Though I have not brought it to a publishable state yet). A single typedef should be sufficient to let it make use of time64_t (it directly uses this type as well as long long internally for its calculations rather than the glibc time format functions). -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2015-11-26 16:30 +0100 |
| Subject | Re: [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding |
| Message-ID | <qz6EH-6XT-37@gated-at.bofh.it> |
| In reply to | #1276728 |
Theodore Ts'o <tytso@mit.edu> wrote: > This is the patch I would prefer to use (and in fact which I have > added to the ext4 tree): > > There are issues with 32-bit vs 64-bit encoding of times before > January 1, 1970, which are handled with this patch which is not > handled with what you have in your patch series. So I'd prefer if you > drop this patch, and I'll get this sent to Linus as a bug fix for 4.4. Fine by me. Acked-by: David Howells <dhowells@redhat.com> -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Martin Steigerwald <martin@lichtvoll.de> |
|---|---|
| Date | 2015-11-20 17:30 +0100 |
| Message-ID | <qwWJs-1a6-11@gated-at.bofh.it> |
| In reply to | #1274142 |
Am Freitag, 20. November 2015, 14:54:22 CET schrieb David Howells: > The seventh patch provides another new system call: > > long ret = fsinfo(int dfd, > const char *filename, > unsigned atflag, > unsigned request, > void *buffer); > > This is an enhanced filesystem stat and information retrieval function that > provides more information, in summary: > > (1) All the information provided by statfs() and more. The fields are > made large. > > (2) Provides information about timestamp range and resolution to > complement statx(). > > (3) Provides information about IOC flags supported in statx()'s return. > > (4) Provides volume binary IDs and UUIDs. > > (5) Provides the filesystem name according to the kernel as a string > (eg. "ext4" or "nfs3") in addition to the magic number. > > (6) Provides information obtained from network filesystems, such as volume > and domain names. > > (7) Has lots of spare space that can be used for future extenstions and a > bit mask indicating what was provided. Any plans to add limitations of filesystem to the call like maximum file size? I know its mostly relevant for just for FAT32, but on any account rather than trying to write 4 GiB and then file, it would be good to at some time get a dialog at the beginning of the copy. Well, but okay, maybe its use case is too limited as FAT32 is not an in any kind modern filesystem anymore and limits of modern filesystems are much higher. But other limits like maximum amount of extended attributes, maximum amount of acls or symlinks on one directory may be nice to query. Symlinks for BTRFS without extended symlink support and acls maybe for XFS, I remember there at least has been a limit at some time that was quite low. Thanks, -- Martin -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2015-11-20 17:30 +0100 |
| Message-ID | <qwWJs-1a6-31@gated-at.bofh.it> |
| In reply to | #1274225 |
Martin Steigerwald <martin@lichtvoll.de> wrote: > Any plans to add limitations of filesystem to the call like maximum file > size? I know its mostly relevant for just for FAT32, but on any account > rather than trying to write 4 GiB and then file, it would be good to at some > time get a dialog at the beginning of the copy. Adding filesystem limits can be done. I got a shopping list of things people wanted a while back and I've worked off of that list. I can add other things - that's on of the reasons I left room for expansion. David -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Martin Steigerwald <martin@lichtvoll.de> |
|---|---|
| Date | 2015-11-20 17:40 +0100 |
| Message-ID | <qwWT8-1dJ-33@gated-at.bofh.it> |
| In reply to | #1274228 |
Cc linux-afs dropped due to bounce:
<linux-afs@vger.kernel.org>: host vger.kernel.org[209.132.180.67] said: 554
5.0.0 Hi [194.150.191.11], unresolvable address:
<linux-afs@vger.kernel.org>; nosuchuser; linux-afs@vger.kernel.org (in
reply to RCPT TO command)
Am Freitag, 20. November 2015, 16:28:35 CET schrieb David Howells:
> Martin Steigerwald <martin@lichtvoll.de> wrote:
> > Any plans to add limitations of filesystem to the call like maximum file
> > size? I know its mostly relevant for just for FAT32, but on any account
> > rather than trying to write 4 GiB and then file, it would be good to at
> > some time get a dialog at the beginning of the copy.
>
> Adding filesystem limits can be done. I got a shopping list of things
> people wanted a while back and I've worked off of that list. I can add
> other things - that's on of the reasons I left room for expansion.
Cool, thank you for bringing this forward.
I am teaching in my Linux trainings since years that one day one will be able
to see file creation time with stat shell command, actually mentioning ideas
to make some xstat/statx system call. :)
Thanks,
--
Martin
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | bfields@fieldses.org (J. Bruce Fields) |
|---|---|
| Date | 2015-11-25 19:00 +0100 |
| Message-ID | <qyMwj-12v-25@gated-at.bofh.it> |
| In reply to | #1274228 |
On Fri, Nov 20, 2015 at 04:28:35PM +0000, David Howells wrote: > Martin Steigerwald <martin@lichtvoll.de> wrote: > > > Any plans to add limitations of filesystem to the call like maximum file > > size? I know its mostly relevant for just for FAT32, but on any account > > rather than trying to write 4 GiB and then file, it would be good to at some > > time get a dialog at the beginning of the copy. > > Adding filesystem limits can be done. I got a shopping list of things people > wanted a while back and I've worked off of that list. I can add other things > - that's on of the reasons I left room for expansion. I ran across systemd/src/basic/path-util.c:fd_is_mount_point() the other day, and the contortions it goes through made me wonder if we should also add mnt_id and/or an is_mountpoint boolean--it's annoying to have to do name_to_handle_at() (not supported on all filesystems) just to get mnt_id. (Looking at it now I see it falls back on reading mount id from /proc/self/fdinfo/<fd>. Maybe that's good enough. May depend on whether there's a potential user that doesn't want to assume access to /proc?) --b. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Dilger <adilger@dilger.ca> |
|---|---|
| Date | 2015-11-25 20:40 +0100 |
| Message-ID | <qyO54-266-17@gated-at.bofh.it> |
| In reply to | #1277663 |
[Multipart message — attachments visible in raw view] — view raw
On Nov 25, 2015, at 10:51 AM, J. Bruce Fields <bfields@fieldses.org> wrote: > > On Fri, Nov 20, 2015 at 04:28:35PM +0000, David Howells wrote: >> Martin Steigerwald <martin@lichtvoll.de> wrote: >> >>> Any plans to add limitations of filesystem to the call like maximum file >>> size? I know its mostly relevant for just for FAT32, but on any account >>> rather than trying to write 4 GiB and then file, it would be good to at some >>> time get a dialog at the beginning of the copy. >> >> Adding filesystem limits can be done. I got a shopping list of things people >> wanted a while back and I've worked off of that list. I can add other things >> - that's on of the reasons I left room for expansion. > > I ran across systemd/src/basic/path-util.c:fd_is_mount_point() the other > day, and the contortions it goes through made me wonder if we should > also add mnt_id and/or an is_mountpoint boolean--it's annoying to have > to do name_to_handle_at() (not supported on all filesystems) just to get > mnt_id. > > (Looking at it now I see it falls back on reading mount id from > /proc/self/fdinfo/<fd>. Maybe that's good enough. May depend on > whether there's a potential user that doesn't want to assume access to > /proc?) IMHO, it should be possible to get information about a file or directory from the file itself (i.e. statx() or fsinfo() on the path/fd), rather than having to grub around in a /proc file that the application magically has to know about, and parse text files there for every file being handled. Cheers, Andreas
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web