Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull VFS fixes from Al Viro:
"statx followup fixes and a fix for stack-smashing on alpha"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
alpha: fix stack smashing in old_adjtimex(2)
statx: Include a mask for stx_attributes in struct statx
statx: Reserve the top bit of the mask for future struct expansion
xfs: report crtime and attribute flags to statx
ext4: Add statx support
statx: optimize copy of struct statx to userspace
statx: remove incorrect part of vfs_statx() comment
statx: reject unknown flags when using NULL path
Documentation/filesystems: fix documentation for ->getattr()

+117 -58
+1 -2
Documentation/filesystems/Locking
··· 58 58 int (*permission) (struct inode *, int, unsigned int); 59 59 int (*get_acl)(struct inode *, int); 60 60 int (*setattr) (struct dentry *, struct iattr *); 61 - int (*getattr) (const struct path *, struct dentry *, struct kstat *, 62 - u32, unsigned int); 61 + int (*getattr) (const struct path *, struct kstat *, u32, unsigned int); 63 62 ssize_t (*listxattr) (struct dentry *, char *, size_t); 64 63 int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); 65 64 void (*update_time)(struct inode *, struct timespec *, int);
+6
Documentation/filesystems/porting
··· 600 600 [recommended] 601 601 ->readlink is optional for symlinks. Don't set, unless filesystem needs 602 602 to fake something for readlink(2). 603 + -- 604 + [mandatory] 605 + ->getattr() is now passed a struct path rather than a vfsmount and 606 + dentry separately, and it now has request_mask and query_flags arguments 607 + to specify the fields and sync type requested by statx. Filesystems not 608 + supporting any statx-specific features may ignore the new arguments.
+1 -2
Documentation/filesystems/vfs.txt
··· 382 382 int (*permission) (struct inode *, int); 383 383 int (*get_acl)(struct inode *, int); 384 384 int (*setattr) (struct dentry *, struct iattr *); 385 - int (*getattr) (const struct path *, struct dentry *, struct kstat *, 386 - u32, unsigned int); 385 + int (*getattr) (const struct path *, struct kstat *, u32, unsigned int); 387 386 ssize_t (*listxattr) (struct dentry *, char *, size_t); 388 387 void (*update_time)(struct inode *, struct timespec *, int); 389 388 int (*atomic_open)(struct inode *, struct dentry *, struct file *,
+1 -1
arch/alpha/kernel/osf_sys.c
··· 1290 1290 /* copy relevant bits of struct timex. */ 1291 1291 if (copy_from_user(&txc, txc_p, offsetof(struct timex32, time)) || 1292 1292 copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) - 1293 - offsetof(struct timex32, time))) 1293 + offsetof(struct timex32, tick))) 1294 1294 return -EFAULT; 1295 1295 1296 1296 ret = do_adjtimex(&txc);
+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,
+38 -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 + 5416 + stat->attributes_mask |= (STATX_ATTR_APPEND | 5417 + STATX_ATTR_COMPRESSED | 5418 + STATX_ATTR_ENCRYPTED | 5419 + STATX_ATTR_IMMUTABLE | 5420 + STATX_ATTR_NODUMP); 5421 + 5397 5422 generic_fillattr(inode, stat); 5423 + return 0; 5424 + } 5425 + 5426 + int ext4_file_getattr(const struct path *path, struct kstat *stat, 5427 + u32 request_mask, unsigned int query_flags) 5428 + { 5429 + struct inode *inode = d_inode(path->dentry); 5430 + u64 delalloc_blocks; 5431 + 5432 + ext4_getattr(path, stat, request_mask, query_flags); 5398 5433 5399 5434 /* 5400 5435 * 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 };
+37 -43
fs/stat.c
··· 130 130 int vfs_statx_fd(unsigned int fd, struct kstat *stat, 131 131 u32 request_mask, unsigned int query_flags) 132 132 { 133 - struct fd f = fdget_raw(fd); 133 + struct fd f; 134 134 int error = -EBADF; 135 135 136 + if (query_flags & ~KSTAT_QUERY_FLAGS) 137 + return -EINVAL; 138 + 139 + f = fdget_raw(fd); 136 140 if (f.file) { 137 141 error = vfs_getattr(&f.file->f_path, stat, 138 142 request_mask, query_flags); ··· 158 154 * that it uses a filename and base directory to determine the file location. 159 155 * Additionally, the use of AT_SYMLINK_NOFOLLOW in flags will prevent a symlink 160 156 * at the given name from being referenced. 161 - * 162 - * The caller must have preset stat->request_mask as for vfs_getattr(). The 163 - * flags are also used to load up stat->query_flags. 164 157 * 165 158 * 0 will be returned on success, and a -ve error code if unsuccessful. 166 159 */ ··· 510 509 } 511 510 #endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */ 512 511 513 - static inline int __put_timestamp(struct timespec *kts, 514 - struct statx_timestamp __user *uts) 512 + static noinline_for_stack int 513 + cp_statx(const struct kstat *stat, struct statx __user *buffer) 515 514 { 516 - return (__put_user(kts->tv_sec, &uts->tv_sec ) || 517 - __put_user(kts->tv_nsec, &uts->tv_nsec ) || 518 - __put_user(0, &uts->__reserved )); 519 - } 515 + struct statx tmp; 520 516 521 - /* 522 - * Set the statx results. 523 - */ 524 - static long statx_set_result(struct kstat *stat, struct statx __user *buffer) 525 - { 526 - uid_t uid = from_kuid_munged(current_user_ns(), stat->uid); 527 - gid_t gid = from_kgid_munged(current_user_ns(), stat->gid); 517 + memset(&tmp, 0, sizeof(tmp)); 528 518 529 - if (__put_user(stat->result_mask, &buffer->stx_mask ) || 530 - __put_user(stat->mode, &buffer->stx_mode ) || 531 - __clear_user(&buffer->__spare0, sizeof(buffer->__spare0)) || 532 - __put_user(stat->nlink, &buffer->stx_nlink ) || 533 - __put_user(uid, &buffer->stx_uid ) || 534 - __put_user(gid, &buffer->stx_gid ) || 535 - __put_user(stat->attributes, &buffer->stx_attributes ) || 536 - __put_user(stat->blksize, &buffer->stx_blksize ) || 537 - __put_user(MAJOR(stat->rdev), &buffer->stx_rdev_major ) || 538 - __put_user(MINOR(stat->rdev), &buffer->stx_rdev_minor ) || 539 - __put_user(MAJOR(stat->dev), &buffer->stx_dev_major ) || 540 - __put_user(MINOR(stat->dev), &buffer->stx_dev_minor ) || 541 - __put_timestamp(&stat->atime, &buffer->stx_atime ) || 542 - __put_timestamp(&stat->btime, &buffer->stx_btime ) || 543 - __put_timestamp(&stat->ctime, &buffer->stx_ctime ) || 544 - __put_timestamp(&stat->mtime, &buffer->stx_mtime ) || 545 - __put_user(stat->ino, &buffer->stx_ino ) || 546 - __put_user(stat->size, &buffer->stx_size ) || 547 - __put_user(stat->blocks, &buffer->stx_blocks ) || 548 - __clear_user(&buffer->__spare1, sizeof(buffer->__spare1)) || 549 - __clear_user(&buffer->__spare2, sizeof(buffer->__spare2))) 550 - return -EFAULT; 519 + tmp.stx_mask = stat->result_mask; 520 + tmp.stx_blksize = stat->blksize; 521 + tmp.stx_attributes = stat->attributes; 522 + tmp.stx_nlink = stat->nlink; 523 + tmp.stx_uid = from_kuid_munged(current_user_ns(), stat->uid); 524 + tmp.stx_gid = from_kgid_munged(current_user_ns(), stat->gid); 525 + tmp.stx_mode = stat->mode; 526 + tmp.stx_ino = stat->ino; 527 + tmp.stx_size = stat->size; 528 + tmp.stx_blocks = stat->blocks; 529 + tmp.stx_attributes_mask = stat->attributes_mask; 530 + tmp.stx_atime.tv_sec = stat->atime.tv_sec; 531 + tmp.stx_atime.tv_nsec = stat->atime.tv_nsec; 532 + tmp.stx_btime.tv_sec = stat->btime.tv_sec; 533 + tmp.stx_btime.tv_nsec = stat->btime.tv_nsec; 534 + tmp.stx_ctime.tv_sec = stat->ctime.tv_sec; 535 + tmp.stx_ctime.tv_nsec = stat->ctime.tv_nsec; 536 + tmp.stx_mtime.tv_sec = stat->mtime.tv_sec; 537 + tmp.stx_mtime.tv_nsec = stat->mtime.tv_nsec; 538 + tmp.stx_rdev_major = MAJOR(stat->rdev); 539 + tmp.stx_rdev_minor = MINOR(stat->rdev); 540 + tmp.stx_dev_major = MAJOR(stat->dev); 541 + tmp.stx_dev_minor = MINOR(stat->dev); 551 542 552 - return 0; 543 + return copy_to_user(buffer, &tmp, sizeof(tmp)) ? -EFAULT : 0; 553 544 } 554 545 555 546 /** ··· 563 570 struct kstat stat; 564 571 int error; 565 572 573 + if (mask & STATX__RESERVED) 574 + return -EINVAL; 566 575 if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE) 567 576 return -EINVAL; 568 - if (!access_ok(VERIFY_WRITE, buffer, sizeof(*buffer))) 569 - return -EFAULT; 570 577 571 578 if (filename) 572 579 error = vfs_statx(dfd, filename, flags, &stat, mask); ··· 574 581 error = vfs_statx_fd(dfd, &stat, mask, flags); 575 582 if (error) 576 583 return error; 577 - return statx_set_result(&stat, buffer); 584 + 585 + return cp_statx(&stat, buffer); 578 586 } 579 587 580 588 /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */
+14
fs/xfs/xfs_iops.c
··· 516 516 stat->blocks = 517 517 XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); 518 518 519 + if (ip->i_d.di_version == 3) { 520 + if (request_mask & STATX_BTIME) { 521 + stat->result_mask |= STATX_BTIME; 522 + stat->btime.tv_sec = ip->i_d.di_crtime.t_sec; 523 + stat->btime.tv_nsec = ip->i_d.di_crtime.t_nsec; 524 + } 525 + } 526 + 527 + if (ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) 528 + stat->attributes |= STATX_ATTR_IMMUTABLE; 529 + if (ip->i_d.di_flags & XFS_DIFLAG_APPEND) 530 + stat->attributes |= STATX_ATTR_APPEND; 531 + if (ip->i_d.di_flags & XFS_DIFLAG_NODUMP) 532 + stat->attributes |= STATX_ATTR_NODUMP; 519 533 520 534 switch (inode->i_mode & S_IFMT) { 521 535 case S_IFBLK:
+1
include/linux/stat.h
··· 26 26 unsigned int nlink; 27 27 uint32_t blksize; /* Preferred I/O size */ 28 28 u64 attributes; 29 + u64 attributes_mask; 29 30 #define KSTAT_ATTR_FS_IOC_FLAGS \ 30 31 (STATX_ATTR_COMPRESSED | \ 31 32 STATX_ATTR_IMMUTABLE | \
+3 -2
include/uapi/linux/stat.h
··· 114 114 __u64 stx_ino; /* Inode number */ 115 115 __u64 stx_size; /* File size */ 116 116 __u64 stx_blocks; /* Number of 512-byte blocks allocated */ 117 - __u64 __spare1[1]; 117 + __u64 stx_attributes_mask; /* Mask to show what's supported in stx_attributes */ 118 118 /* 0x40 */ 119 119 struct statx_timestamp stx_atime; /* Last access time */ 120 120 struct statx_timestamp stx_btime; /* File creation time */ ··· 152 152 #define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */ 153 153 #define STATX_BTIME 0x00000800U /* Want/got stx_btime */ 154 154 #define STATX_ALL 0x00000fffU /* All currently supported flags */ 155 + #define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */ 155 156 156 157 /* 157 - * Attributes to be found in stx_attributes 158 + * Attributes to be found in stx_attributes and masked in stx_attributes_mask. 158 159 * 159 160 * These give information about the features or the state of a file that might 160 161 * be of use to ordinary userspace programs such as GUIs or ls rather than
+8 -4
samples/statx/test-statx.c
··· 141 141 if (stx->stx_mask & STATX_BTIME) 142 142 print_time(" Birth: ", &stx->stx_btime); 143 143 144 - if (stx->stx_attributes) { 145 - unsigned char bits; 144 + if (stx->stx_attributes_mask) { 145 + unsigned char bits, mbits; 146 146 int loop, byte; 147 147 148 148 static char attr_representation[64 + 1] = ··· 160 160 printf("Attributes: %016llx (", stx->stx_attributes); 161 161 for (byte = 64 - 8; byte >= 0; byte -= 8) { 162 162 bits = stx->stx_attributes >> byte; 163 + mbits = stx->stx_attributes_mask >> byte; 163 164 for (loop = 7; loop >= 0; loop--) { 164 165 int bit = byte + loop; 165 166 166 - if (bits & 0x80) 167 + if (!(mbits & 0x80)) 168 + putchar('.'); /* Not supported */ 169 + else if (bits & 0x80) 167 170 putchar(attr_representation[63 - bit]); 168 171 else 169 - putchar('-'); 172 + putchar('-'); /* Not set */ 170 173 bits <<= 1; 174 + mbits <<= 1; 171 175 } 172 176 if (byte) 173 177 putchar(' ');