ext4: Add statx support

Return enhanced file attributes from the Ext4 filesystem. This includes
the following:

(1) The inode creation time (i_crtime) as stx_btime, setting STATX_BTIME.

(2) Certain FS_xxx_FL flags are mapped to stx_attribute flags.

This requires that all ext4 inodes have a getattr call, not just some of
them, so to this end, split the ext4_getattr() function and only call part
of it where appropriate.

Example output:

[root@andromeda ~]# touch foo
[root@andromeda ~]# chattr +ai foo
[root@andromeda ~]# /tmp/test-statx foo
statx(foo) = 0
results=fff
Size: 0 Blocks: 0 IO Block: 4096 regular file
Device: 08:12 Inode: 2101950 Links: 1
Access: (0644/-rw-r--r--) Uid: 0 Gid: 0
Access: 2016-02-11 17:08:29.031795451+0000
Modify: 2016-02-11 17:08:29.031795451+0000
Change: 2016-02-11 17:11:11.987790114+0000
Birth: 2016-02-11 17:08:29.031795451+0000
Attributes: 0000000000000030 (-------- -------- -------- -------- -------- -------- -------- --ai----)

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

authored by David Howells and committed by Al Viro 99652ea5 64bd7204

+39 -4
+1
fs/ext4/ext4.h
··· 2466 2466 extern int ext4_getattr(const struct path *, struct kstat *, u32, unsigned int); 2467 2467 extern void ext4_evict_inode(struct inode *); 2468 2468 extern void ext4_clear_inode(struct inode *); 2469 + extern int ext4_file_getattr(const struct path *, struct kstat *, u32, unsigned int); 2469 2470 extern int ext4_sync_inode(handle_t *, struct inode *); 2470 2471 extern void ext4_dirty_inode(struct inode *, int); 2471 2472 extern int ext4_change_inode_journal_flag(struct inode *, int);
+1 -1
fs/ext4/file.c
··· 744 744 745 745 const struct inode_operations ext4_file_inode_operations = { 746 746 .setattr = ext4_setattr, 747 - .getattr = ext4_getattr, 747 + .getattr = ext4_file_getattr, 748 748 .listxattr = ext4_listxattr, 749 749 .get_acl = ext4_get_acl, 750 750 .set_acl = ext4_set_acl,
+32 -3
fs/ext4/inode.c
··· 5390 5390 int ext4_getattr(const struct path *path, struct kstat *stat, 5391 5391 u32 request_mask, unsigned int query_flags) 5392 5392 { 5393 - struct inode *inode; 5394 - unsigned long long delalloc_blocks; 5393 + struct inode *inode = d_inode(path->dentry); 5394 + struct ext4_inode *raw_inode; 5395 + struct ext4_inode_info *ei = EXT4_I(inode); 5396 + unsigned int flags; 5395 5397 5396 - inode = d_inode(path->dentry); 5398 + if (EXT4_FITS_IN_INODE(raw_inode, ei, i_crtime)) { 5399 + stat->result_mask |= STATX_BTIME; 5400 + stat->btime.tv_sec = ei->i_crtime.tv_sec; 5401 + stat->btime.tv_nsec = ei->i_crtime.tv_nsec; 5402 + } 5403 + 5404 + flags = ei->i_flags & EXT4_FL_USER_VISIBLE; 5405 + if (flags & EXT4_APPEND_FL) 5406 + stat->attributes |= STATX_ATTR_APPEND; 5407 + if (flags & EXT4_COMPR_FL) 5408 + stat->attributes |= STATX_ATTR_COMPRESSED; 5409 + if (flags & EXT4_ENCRYPT_FL) 5410 + stat->attributes |= STATX_ATTR_ENCRYPTED; 5411 + if (flags & EXT4_IMMUTABLE_FL) 5412 + stat->attributes |= STATX_ATTR_IMMUTABLE; 5413 + if (flags & EXT4_NODUMP_FL) 5414 + stat->attributes |= STATX_ATTR_NODUMP; 5415 + 5397 5416 generic_fillattr(inode, stat); 5417 + return 0; 5418 + } 5419 + 5420 + int ext4_file_getattr(const struct path *path, struct kstat *stat, 5421 + u32 request_mask, unsigned int query_flags) 5422 + { 5423 + struct inode *inode = d_inode(path->dentry); 5424 + u64 delalloc_blocks; 5425 + 5426 + ext4_getattr(path, stat, request_mask, query_flags); 5398 5427 5399 5428 /* 5400 5429 * If there is inline data in the inode, the inode will normally not
+2
fs/ext4/namei.c
··· 3912 3912 .tmpfile = ext4_tmpfile, 3913 3913 .rename = ext4_rename2, 3914 3914 .setattr = ext4_setattr, 3915 + .getattr = ext4_getattr, 3915 3916 .listxattr = ext4_listxattr, 3916 3917 .get_acl = ext4_get_acl, 3917 3918 .set_acl = ext4_set_acl, ··· 3921 3920 3922 3921 const struct inode_operations ext4_special_inode_operations = { 3923 3922 .setattr = ext4_setattr, 3923 + .getattr = ext4_getattr, 3924 3924 .listxattr = ext4_listxattr, 3925 3925 .get_acl = ext4_get_acl, 3926 3926 .set_acl = ext4_set_acl,
+3
fs/ext4/symlink.c
··· 85 85 const struct inode_operations ext4_encrypted_symlink_inode_operations = { 86 86 .get_link = ext4_encrypted_get_link, 87 87 .setattr = ext4_setattr, 88 + .getattr = ext4_getattr, 88 89 .listxattr = ext4_listxattr, 89 90 }; 90 91 91 92 const struct inode_operations ext4_symlink_inode_operations = { 92 93 .get_link = page_get_link, 93 94 .setattr = ext4_setattr, 95 + .getattr = ext4_getattr, 94 96 .listxattr = ext4_listxattr, 95 97 }; 96 98 97 99 const struct inode_operations ext4_fast_symlink_inode_operations = { 98 100 .get_link = simple_get_link, 99 101 .setattr = ext4_setattr, 102 + .getattr = ext4_getattr, 100 103 .listxattr = ext4_listxattr, 101 104 };