On 2012-04-24, at 4:29 PM, J. Bruce Fields wrote:
> On Thu, Apr 19, 2012 at 03:06:12PM +0100, David Howells wrote:
>> (11) Include granularity fields in the time data to indicate the
>>    granularity of each of the times (NFSv4 time_delta) [Steve French].
> 
> It looks like you're including this with *each* time?  But surely
> there's no filesystem with different granularity (say) for ctime than
> for mtime.  Also, nfsd will want only one time_delta, not one for each
> time.

I suspect the main reason for having a separate time_delta per timestamp
is to use the extra 32-bit field in the timestamp structs.  Since those
structs have a 64-bit + 32-bit field, it would be messy to pack them,
and leaving the spare bytes unused and adding an additional field for
the granularity would just increase the struct size.

> Note also we need to document carefully what this means: I think it
> should be the granularity that the filesystem is capable of
> representing, but people are sometimes surprised to find out that the
> actual time source is usually more coarse-grained than that.
> 
> --b.
> 
>> 
>> (12) FS_IOC_GETFLAGS value.  These could be translated to BSD's st_flags.
>> 
>> (13) Mask of features available on file (eg: ACLs, seclabel) [Brad Boyer,
>>    Michael Kerrisk].
>> 
>> (14) Spare space, request flags and information flags are provided for future
>>    expansion.
>> 
>> 
>> The following structures are defined for the use of these new system calls:
>> 
>>      struct xstat_dev {
>>              uint32_t                major, minor;
>>      };
>> 
>>      struct xstat_time {
>>              uint64_t                tv_sec;
>>              uint32_t                tv_nsec;
>>              uint32_t                tv_granularity;
>>      };
>> 
>>      struct xstat {
>>              uint32_t                st_mask;
>>              uint32_t                st_mode;
>>              uint32_t                st_nlink;
>>              uint32_t                st_uid;
>>              uint32_t                st_gid;
>>              uint32_t                st_information;
>>              uint32_t                st_ioc_flags;
>>              uint32_t                st_blksize;
>>              struct xstat_dev        st_rdev;
>>              struct xstat_dev        st_dev;
>>              struct xstat_time       st_atime;
>>              struct xstat_time       st_btime;
>>              struct xstat_time       st_ctime;
>>              struct xstat_time       st_mtime;
>>              uint64_t                st_ino;
>>              uint64_t                st_size;
>>              uint64_t                st_blocks;
>>              uint64_t                st_gen;
>>              uint64_t                st_version;
>>              uint8_t                 st_volume_id[16];
>>              uint64_t                __spares[11];
>>      };
>> 
>> where st_information is local system information about the file, st_btime is
>> the file creation time, st_gen is the inode generation (i_generation),
>> st_data_version is the data version number (i_version), st_ioc_flags is the
>> flags from FS_IOC_GETFLAGS, st_volume_id is where the volume identified is
>> stored, st_result_mask is a bitmask indicating the data provided and 
>> __spares[]
>> are where as-yet undefined fields can be placed.
>> 
>> The defined bits in request_mask and st_mask are:
>> 
>>      XSTAT_MODE              Want/got st_mode
>>      XSTAT_NLINK             Want/got st_nlink
>>      XSTAT_UID               Want/got st_uid
>>      XSTAT_GID               Want/got st_gid
>>      XSTAT_RDEV              Want/got st_rdev
>>      XSTAT_ATIME             Want/got st_atime
>>      XSTAT_MTIME             Want/got st_mtime
>>      XSTAT_CTIME             Want/got st_ctime
>>      XSTAT_INO               Want/got st_ino
>>      XSTAT_SIZE              Want/got st_size
>>      XSTAT_BLOCKS            Want/got st_blocks
>>      XSTAT_BASIC_STATS       [The stuff in the normal stat struct]
>>      XSTAT_IOC_FLAGS         Want/got FS_IOC_GETFLAGS
>>      XSTAT_BTIME             Want/got st_btime
>>      XSTAT_GEN               Want/got st_gen
>>      XSTAT_VERSION           Want/got st_data_version
>>      XSTAT_VOLUME_ID         Want/got st_volume_id
>>      XSTAT_ALL_STATS         [All currently available stuff]
>> 
>> The defined bits in st_ioc_flags are the usual FS_xxx_FL, plus some extra 
>> flags
>> that might be supplied by the filesystem.  Note that Ext4 returns flags 
>> outside
>> of {EXT4,FS}_FL_USER_VISIBLE in response to FS_IOC_GETFLAGS.  Should
>> {EXT4,FS}_FL_USER_VISIBLE be extended to cover them?  Or should the extra 
>> flags
>> be suppressed?
>> 
>> The defined bits in the st_information field give local system data on a 
>> file,
>> how it is accessed, where it is and what it does:
>> 
>>      XSTAT_INFO_ENCRYPTED            File is encrypted
>>      XSTAT_INFO_TEMPORARY            File is temporary (NTFS/CIFS/deleted)
>>      XSTAT_INFO_FABRICATED           File was made up by filesystem
>>      XSTAT_INFO_KERNEL_API           File is kernel API (eg: procfs/sysfs)
>>      XSTAT_INFO_REMOTE               File is remote
>>      XSTAT_INFO_OFFLINE              File is offline (CIFS)
>>      XSTAT_INFO_AUTOMOUNT            Dir is automount trigger
>>      XSTAT_INFO_AUTODIR              Dir provides unlisted automounts
>>      XSTAT_INFO_NONSYSTEM_OWNERSHIP  File has non-system ownership details
>>      XSTAT_INFO_HAS_ACL              File has an ACL of some sort
>>      XSTAT_INFO_REPARSE_POINT        File is reparse point (NTFS/CIFS)
>>      XSTAT_INFO_HIDDEN               File is marked hidden (DOS+)
>>      XSTAT_INFO_SYSTEM               File is marked system (DOS+)
>>      XSTAT_INFO_ARCHIVE              File is marked archive (DOS+)
>> 
>> These are for the use of GUI tools that might want to mark files specially,
>> depending on what they are.  I've tried not to provide overlap with
>> st_ioc_flags where something usable exists there.  Should Hidden, System and
>> Archive flags be associated with ioc_flags, perhaps with ioc_flags extended 
>> to
>> 64-bits?
>> 
>> 
>> The system calls are:
>> 
>>      ssize_t ret = xstat(int dfd,
>>                          const char *filename,
>>                          unsigned int flags,
>>                          unsigned int mask,
>>                          struct xstat *buffer);
>> 
>>      ssize_t ret = fxstat(unsigned fd,
>>                           unsigned int flags,
>>                           unsigned int mask,
>>                           struct xstat *buffer);
>> 
>> 
>> The dfd, filename, flags and fd parameters indicate the file to query.  There
>> is no equivalent of lstat() as that can be emulated with xstat() by passing
>> AT_SYMLINK_NOFOLLOW in flags.
>> 
>> AT_FORCE_ATTR_SYNC can also be set in flags.  This will require a network
>> filesystem to synchronise its attributes with the server.
>> 
>> mask is a bitmask indicating the fields in struct xstat that are of interest 
>> to
>> the caller.  The user should set this to XSTAT__BASIC_STATS to get the
>> basic set returned by stat().
>> 
>> Should there just be one xstat() syscall that does fxstat() if filename is 
>> NULL?
>> 
>> The fields in struct xstat come in a number of classes:
>> 
>> (0) st_dev, st_blksize, st_information.
>> 
>>    These are local data and are always available.
>> 
>> (1) st_mode, st_nlinks, st_uid, st_gid, st_[amc]time, st_ino, st_size,
>>    st_blocks.
>> 
>>    These will be returned whether the caller asks for them or not.  The
>>    corresponding bits in result_mask will be set to indicate their presence.
>> 
>>    If the caller didn't ask for them, then they may be approximated.  For
>>    example, NFS won't waste any time updating them from the server, unless as
>>    a byproduct of updating something requested.
>> 
>>    If the values don't actually exist for the underlying object (such as UID
>>    or GID on a DOS file), then the bit won't be set in the result_mask, even
>>    if the caller asked for the value and the returned value will be a
>>    fabrication.
>> 
>> (2) st_rdev.
>> 
>>    As for class (1), but this won't be returned if the file is not a blockdev
>>    or chardev.  The bit will be cleared if the value is not returned.
>> 
>> (3) File creation time (st_btime), inode generation (st_gen), data version
>>    (st_version), volume_id (st_volume_id) and inode flags (st_ioc_flags).
>> 
>>    These will be returned if available whether the caller asked for them or
>>    not.  The corresponding bits in result_mask will be set or cleared as
>>    appropriate to indicate their presence.
>> 
>>    If the caller didn't ask for them, then they may be approximated.  For
>>    example, NFS won't waste any time updating them from the server, unless
>>    as a byproduct of updating something requested.
>> 
>> At the moment, this will only work on x86_64 and i386 as it requires system
>> calls to be wired up.
>> 
>> 
>> =======
>> TESTING
>> =======
>> 
>> The following test program can be used to test the xstat system call:
>> 
>>      /* Test the xstat() system call
>>       *
>>       * Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
>>       * Written by David Howells (dhowe...@redhat.com)
>>       *
>>       * This program is free software; you can redistribute it and/or
>>       * modify it under the terms of the GNU General Public Licence
>>       * as published by the Free Software Foundation; either version
>>       * 2 of the Licence, or (at your option) any later version.
>>       */
>> 
>>      #define _GNU_SOURCE
>>      #define _ATFILE_SOURCE
>>      #include <stdio.h>
>>      #include <stdlib.h>
>>      #include <string.h>
>>      #include <unistd.h>
>>      #include <fcntl.h>
>>      #include <time.h>
>>      #include <sys/syscall.h>
>>      #include <sys/stat.h>
>>      #include <sys/types.h>
>> 
>>      #define AT_NO_AUTOMOUNT         0x800
>>      #define AT_FORCE_ATTR_SYNC      0x2000
>> 
>>      #define XSTAT_MODE              0x00000001U
>>      #define XSTAT_NLINK             0x00000002U
>>      #define XSTAT_UID               0x00000004U
>>      #define XSTAT_GID               0x00000008U
>>      #define XSTAT_RDEV              0x00000010U
>>      #define XSTAT_ATIME             0x00000020U
>>      #define XSTAT_MTIME             0x00000040U
>>      #define XSTAT_CTIME             0x00000080U
>>      #define XSTAT_INO               0x00000100U
>>      #define XSTAT_SIZE              0x00000200U
>>      #define XSTAT_BLOCKS            0x00000400U
>>      #define XSTAT_BASIC_STATS       0x000007ffU
>>      #define XSTAT_BTIME             0x00000800U
>>      #define XSTAT_GEN               0x00001000U
>>      #define XSTAT_VERSION           0x00002000U
>>      #define XSTAT_IOC_FLAGS         0x00004000U
>>      #define XSTAT_VOLUME_ID         0x00008000U
>>      #define XSTAT_ALL_STATS         0x0000ffffU
>> 
>>      struct xstat_dev {
>>              uint32_t                major;
>>              uint32_t                minor;
>>      };
>> 
>>      struct xstat_time {
>>              uint64_t                tv_sec;
>>              uint32_t                tv_nsec;
>>              uint32_t                tv_granularity;
>>      };
>> 
>>      struct xstat {
>>              uint32_t                st_mask;
>>              uint32_t                st_mode;
>>              uint32_t                st_nlink;
>>              uint32_t                st_uid;
>>              uint32_t                st_gid;
>>              uint32_t                st_information;
>>              uint32_t                st_ioc_flags;
>>              uint32_t                st_blksize;
>>              struct xstat_dev        st_rdev;
>>              struct xstat_dev        st_dev;
>>              struct xstat_time       st_atim;
>>              struct xstat_time       st_btim;
>>              struct xstat_time       st_ctim;
>>              struct xstat_time       st_mtim;
>>              uint64_t                st_ino;
>>              uint64_t                st_size;
>>              uint64_t                st_blksize;
>>              uint64_t                st_blocks;
>>              uint64_t                st_gen;
>>              uint64_t                st_version;
>>              uint64_t                st_volume_id[16];
>>              uint64_t                st_spares[11];
>>      };
>> 
>>      #define XSTAT_INFO_ENCRYPTED            0x00000001U
>>      #define XSTAT_INFO_TEMPORARY            0x00000002U
>>      #define XSTAT_INFO_FABRICATED           0x00000004U
>>      #define XSTAT_INFO_KERNEL_API           0x00000008U
>>      #define XSTAT_INFO_REMOTE               0x00000010U
>>      #define XSTAT_INFO_OFFLINE              0x00000020U
>>      #define XSTAT_INFO_AUTOMOUNT            0x00000040U
>>      #define XSTAT_INFO_AUTODIR              0x00000080U
>>      #define XSTAT_INFO_NONSYSTEM_OWNERSHIP  0x00000100U
>>      #define XSTAT_INFO_HAS_ACL              0x00000200U
>>      #define XSTAT_INFO_REPARSE_POINT        0x00000400U
>>      #define XSTAT_INFO_HIDDEN               0x00000800U
>>      #define XSTAT_INFO_SYSTEM               0x00001000U
>>      #define XSTAT_INFO_ARCHIVE              0x00002000U
>> 
>>      #define __NR_xstat                              312
>>      #define __NR_fxstat                             313
>> 
>>      static __attribute__((unused))
>>      ssize_t xstat(int dfd, const char *filename, unsigned flags,
>>                    unsigned int mask, struct xstat *buffer)
>>      {
>>              return syscall(__NR_xstat, dfd, filename, flags, mask, buffer);
>>      }
>> 
>>      static __attribute__((unused))
>>      ssize_t fxstat(int fd, unsigned flags,
>>                     unsigned int mask, struct xstat *buffer)
>>      {
>>              return syscall(__NR_fxstat, fd, flags, mask, buffer);
>>      }
>> 
>>      static void print_time(const char *field, const struct xstat_time *xstm)
>>      {
>>              struct tm tm;
>>              time_t tim;
>>              char buffer[100];
>>              int len;
>> 
>>              tim = xstm->tv_sec;
>>              if (!localtime_r(&tim, &tm)) {
>>                      perror("localtime_r");
>>                      exit(1);
>>              }
>>              len = strftime(buffer, 100, "%F %T", &tm);
>>              if (len == 0) {
>>                      perror("strftime");
>>                      exit(1);
>>              }
>>              printf("%s", field);
>>              fwrite(buffer, 1, len, stdout);
>>              printf(".%09u", xstm->tv_nsec);
>>              len = strftime(buffer, 100, "%z", &tm);
>>              if (len == 0) {
>>                      perror("strftime2");
>>                      exit(1);
>>              }
>>              fwrite(buffer, 1, len, stdout);
>>              printf("\n");
>>      }
>> 
>>      static void dump_xstat(struct xstat *xst)
>>      {
>>              char buffer[256], ft;
>> 
>>              printf("results=%x\n", xst->st_mask);
>> 
>>              printf(" ");
>>              if (xst->st_mask & XSTAT_SIZE)
>>                      printf(" Size: %-15llu", (unsigned long long) 
>> xst->st_size);
>>              if (xst->st_mask & XSTAT_BLOCKS)
>>                      printf(" Blocks: %-10llu", (unsigned long long) 
>> xst->st_blocks);
>>              printf(" IO Block: %-6llu ", (unsigned long long) 
>> xst->st_blksize);
>>              if (xst->st_mask & XSTAT_MODE) {
>>                      switch (xst->st_mode & S_IFMT) {
>>                      case S_IFIFO:   printf(" FIFO\n");                      
>> ft = 'p'; break;
>>                      case S_IFCHR:   printf(" character special file\n");    
>> ft = 'c'; break;
>>                      case S_IFDIR:   printf(" directory\n");                 
>> ft = 'd'; break;
>>                      case S_IFBLK:   printf(" block special file\n");        
>> ft = 'b'; break;
>>                      case S_IFREG:   printf(" regular file\n");              
>> ft = '-'; break;
>>                      case S_IFLNK:   printf(" symbolic link\n");             
>> ft = 'l'; break;
>>                      case S_IFSOCK:  printf(" socket\n");                    
>> ft = 's'; break;
>>                      default:
>>                              printf("unknown type (%o)\n", xst->st_mode & 
>> S_IFMT);
>>                              ft = '?';
>>                              break;
>>                      }
>>              }
>> 
>>              sprintf(buffer, "%02x:%02x", xst->st_dev.major, 
>> xst->st_dev.minor);
>>              printf("Device: %-15s", buffer);
>>              if (xst->st_mask & XSTAT_INO)
>>                      printf(" Inode: %-11llu", (unsigned long long) 
>> xst->st_ino);
>>              if (xst->st_mask & XSTAT_SIZE)
>>                      printf(" Links: %-5u", xst->st_nlink);
>>              if (xst->st_mask & XSTAT_RDEV)
>>                      printf(" Device type: %u,%u",
>>                             xst->st_rdev.major, xst->st_rdev.minor);
>>              printf("\n");
>> 
>>              if (xst->st_mask & XSTAT_MODE)
>>                      printf("Access: (%04o/%c%c%c%c%c%c%c%c%c%c)  ",
>>                             xst->st_mode & 07777,
>>                             ft,
>>                             xst->st_mode & S_IRUSR ? 'r' : '-',
>>                             xst->st_mode & S_IWUSR ? 'w' : '-',
>>                             xst->st_mode & S_IXUSR ? 'x' : '-',
>>                             xst->st_mode & S_IRGRP ? 'r' : '-',
>>                             xst->st_mode & S_IWGRP ? 'w' : '-',
>>                             xst->st_mode & S_IXGRP ? 'x' : '-',
>>                             xst->st_mode & S_IROTH ? 'r' : '-',
>>                             xst->st_mode & S_IWOTH ? 'w' : '-',
>>                             xst->st_mode & S_IXOTH ? 'x' : '-');
>>              if (xst->st_mask & XSTAT_UID)
>>                      printf("Uid: %d   \n", xst->st_uid);
>>              if (xst->st_mask & XSTAT_GID)
>>                      printf("Gid: %u\n", xst->st_gid);
>> 
>>              if (xst->st_mask & XSTAT_ATIME)
>>                      print_time("Access: ", &xst->st_atim);
>>              if (xst->st_mask & XSTAT_MTIME)
>>                      print_time("Modify: ", &xst->st_mtim);
>>              if (xst->st_mask & XSTAT_CTIME)
>>                      print_time("Change: ", &xst->st_ctim);
>>              if (xst->st_mask & XSTAT_BTIME)
>>                      print_time("Create: ", &xst->st_btim);
>> 
>>              if (xst->st_mask & XSTAT_GEN)
>>                      printf("Inode version: %llxh\n", (unsigned long long) 
>> xst->st_gen);
>>              if (xst->st_mask & XSTAT_VERSION)
>>                      printf("Data version: %llxh\n", (unsigned long long) 
>> xst->st_version);
>> 
>>              if (xst->st_mask & XSTAT_IOC_FLAGS) {
>>                      unsigned char bits;
>>                      int loop, byte;
>> 
>>                      static char flag_representation[32 + 1] =
>>                              /* FS_IOC_GETFLAGS flags: */
>>                              "????????"      /* 31-24        
>> 0x00000000-ff000000  */
>>                              "????ehTD"      /* 23-16        
>> 0x00000000-00ff0000  */
>>                              "tj?IE?XZ"      /* 15- 8        
>> 0x00000000-0000ff00  */
>>                              "AdaiScus"      /*  7- 0        
>> 0x00000000-000000ff */
>>                              ;
>> 
>>                      printf("Inode flags: %08x (", xst->st_ioc_flags);
>>                      for (byte = 32 - 8; byte >= 0; byte -= 8) {
>>                              bits = xst->st_ioc_flags >> byte;
>>                              for (loop = 7; loop >= 0; loop--) {
>>                                      int bit = byte + loop;
>> 
>>                                      if (bits & 0x80)
>>                                              putchar(flag_representation[31 
>> - bit]);
>>                                      else
>>                                              putchar('-');
>>                                      bits <<= 1;
>>                              }
>>                              if (byte)
>>                                      putchar(' ');
>>                      }
>>                      printf(")\n");
>>              }
>> 
>>              if (xst->st_information) {
>>                      unsigned char bits;
>>                      int loop, byte;
>> 
>>                      static char info_representation[32 + 1] =
>>                              /* XSTAT_INFO_ flags: */
>>                              "????????"      /* 31-24        
>> 0x00000000-ff000000  */
>>                              "????????"      /* 23-16        
>> 0x00000000-00ff0000  */
>>                              "??ASHRan"      /* 15- 8        
>> 0x00000000-0000ff00  */
>>                              "dmorkfte"      /*  7- 0        
>> 0x00000000-000000ff */
>>                              ;
>> 
>>                      printf("Information: %08x (", xst->st_information);
>>                      for (byte = 32 - 8; byte >= 0; byte -= 8) {
>>                              bits = xst->st_information >> byte;
>>                              for (loop = 7; loop >= 0; loop--) {
>>                                      int bit = byte + loop;
>> 
>>                                      if (bits & 0x80)
>>                                              putchar(info_representation[31 
>> - bit]);
>>                                      else
>>                                              putchar('-');
>>                                      bits <<= 1;
>>                              }
>>                              if (byte)
>>                                      putchar(' ');
>>                      }
>>                      printf(")\n");
>>              }
>> 
>>              if (xst->st_mask & XSTAT_VOLUME_ID) {
>>                      int loop;
>>                      printf("Volume ID: ");
>>                      for (loop = 0; loop < sizeof(xst->st_volume_id); 
>> loop++) {
>>                              printf("%02x", xst->st_volume_id[loop]);
>>                              if (loop == 7)
>>                                      printf("-");
>>                      }
>>                      printf("\n");
>>              }
>>      }
>> 
>>      void dump_hex(unsigned long long *data, int from, int to)
>>      {
>>              unsigned offset, print_offset = 1, col = 0;
>> 
>>              from /= 8;
>>              to = (to + 7) / 8;
>> 
>>              for (offset = from; offset < to; offset++) {
>>                      if (print_offset) {
>>                              printf("%04x: ", offset * 8);
>>                              print_offset = 0;
>>                      }
>>                      printf("%016llx", data[offset]);
>>                      col++;
>>                      if ((col & 3) == 0) {
>>                              printf("\n");
>>                              print_offset = 1;
>>                      } else {
>>                              printf(" ");
>>                      }
>>              }
>> 
>>              if (!print_offset)
>>                      printf("\n");
>>      }
>> 
>>      int main(int argc, char **argv)
>>      {
>>              struct xstat xst;
>>              int ret, raw = 0, atflag = AT_SYMLINK_NOFOLLOW;
>> 
>>              unsigned int mask = XSTAT_ALL_STATS;
>> 
>>              for (argv++; *argv; argv++) {
>>                      if (strcmp(*argv, "-F") == 0) {
>>                              atflag |= AT_FORCE_ATTR_SYNC;
>>                              continue;
>>                      }
>>                      if (strcmp(*argv, "-L") == 0) {
>>                              atflag &= ~AT_SYMLINK_NOFOLLOW;
>>                              continue;
>>                      }
>>                      if (strcmp(*argv, "-O") == 0) {
>>                              mask &= ~XSTAT_BASIC_STATS;
>>                              continue;
>>                      }
>>                      if (strcmp(*argv, "-A") == 0) {
>>                              atflag |= AT_NO_AUTOMOUNT;
>>                              continue;
>>                      }
>>                      if (strcmp(*argv, "-R") == 0) {
>>                              raw = 1;
>>                              continue;
>>                      }
>> 
>>                      memset(&xst, 0xbf, sizeof(xst));
>>                      ret = xstat(AT_FDCWD, *argv, atflag, mask, &xst);
>>                      printf("xstat(%s) = %d\n", *argv, ret);
>>                      if (ret < 0) {
>>                              perror(*argv);
>>                              exit(1);
>>                      }
>> 
>>                      if (raw)
>>                              dump_hex((unsigned long long *)&xst, 0, 
>> sizeof(xst));
>> 
>>                      dump_xstat(&xst);
>>              }
>>              return 0;
>>      }
>> 
>> Just compile and run, passing it paths to the files you want to examine:
>> 
>>      [root@andromeda ~]# /tmp/xstat /proc/$$
>>      xstat(/proc/2074) = 160
>>      results=47ef
>>        Size: 0               Blocks: 0          IO Block: 1024    directory
>>      Device: 00:03           Inode: 9072        Links: 7
>>      Access: (0555/dr-xr-xr-x)  Uid: 0
>>      Gid: 0
>>      Access: 2010-07-14 16:50:46.609336272+0100
>>      Modify: 2010-07-14 16:50:46.609336272+0100
>>      Change: 2010-07-14 16:50:46.609336272+0100
>>      Inode flags: 0000000100000000 (-------- -------- -------- -------S 
>> -------- -------- -------- --------)
>>      [root@andromeda ~]# /tmp/xstat 
>> /afs/archive/linuxdev/fedora9/x86_64/kernel-devel-2.6.25.10-86.fc9.x86_64.rpm
>>      
>> xstat(/afs/archive/linuxdev/fedora9/x86_64/kernel-devel-2.6.25.10-86.fc9.x86_64.rpm)
>>  = 160
>>      results=77ef
>>        Size: 5413882         Blocks: 0          IO Block: 4096    regular 
>> file
>>      Device: 00:15           Inode: 2288        Links: 1
>>      Access: (0644/-rw-r--r--)  Uid: 75338
>>      Gid: 0
>>      Access: 2008-11-05 19:47:22.000000000+0000
>>      Modify: 2008-11-05 19:47:22.000000000+0000
>>      Change: 2008-11-05 19:47:22.000000000+0000
>>      Inode version: 795h
>>      Data version: 2h
>>      Inode flags: 0000000800000000 (-------- -------- -------- ----r--- 
>> -------- -------- -------- --------)
>> 
>> Signed-off-by: David Howells <dhowe...@redhat.com>
>> ---
>> 
>> arch/x86/syscalls/syscall_32.tbl |    2 
>> arch/x86/syscalls/syscall_64.tbl |    2 
>> fs/stat.c                        |  350 
>> +++++++++++++++++++++++++++++++++++---
>> include/linux/fcntl.h            |    1 
>> include/linux/fs.h               |    4 
>> include/linux/stat.h             |  126 +++++++++++++-
>> include/linux/syscalls.h         |    7 +
>> 7 files changed, 461 insertions(+), 31 deletions(-)
>> 
>> diff --git a/arch/x86/syscalls/syscall_32.tbl 
>> b/arch/x86/syscalls/syscall_32.tbl
>> index 29f9f05..980eb5a 100644
>> --- a/arch/x86/syscalls/syscall_32.tbl
>> +++ b/arch/x86/syscalls/syscall_32.tbl
>> @@ -355,3 +355,5 @@
>> 346  i386    setns                   sys_setns
>> 347  i386    process_vm_readv        sys_process_vm_readv            
>> compat_sys_process_vm_readv
>> 348  i386    process_vm_writev       sys_process_vm_writev           
>> compat_sys_process_vm_writev
>> +349 i386    xstat                   sys_xstat
>> +350 i386    fxstat                  sys_fxstat
>> diff --git a/arch/x86/syscalls/syscall_64.tbl 
>> b/arch/x86/syscalls/syscall_64.tbl
>> index dd29a9e..7ae24bb 100644
>> --- a/arch/x86/syscalls/syscall_64.tbl
>> +++ b/arch/x86/syscalls/syscall_64.tbl
>> @@ -318,6 +318,8 @@
>> 309  common  getcpu                  sys_getcpu
>> 310  64      process_vm_readv        sys_process_vm_readv
>> 311  64      process_vm_writev       sys_process_vm_writev
>> +312 common  xstat                   sys_xstat
>> +313 common  fxstat                  sys_fxstat
>> #
>> # x32-specific system call numbers start at 512 to avoid cache impact
>> # for native 64-bit operation.
>> diff --git a/fs/stat.c b/fs/stat.c
>> index c733dc5..af3ef33 100644
>> --- a/fs/stat.c
>> +++ b/fs/stat.c
>> @@ -18,8 +18,20 @@
>> #include <asm/uaccess.h>
>> #include <asm/unistd.h>
>> 
>> +/**
>> + * generic_fillattr - Fill in the basic attributes from the inode struct
>> + * @inode: Inode to use as the source
>> + * @stat: Where to fill in the attributes
>> + *
>> + * Fill in the basic attributes in the kstat structure from data that's to 
>> be
>> + * found on the VFS inode structure.  This is the default if no getattr 
>> inode
>> + * operation is supplied.
>> + */
>> void generic_fillattr(struct inode *inode, struct kstat *stat)
>> {
>> +    struct super_block *sb = inode->i_sb;
>> +    u32 x;
>> +
>>      stat->dev = inode->i_sb->s_dev;
>>      stat->ino = inode->i_ino;
>>      stat->mode = inode->i_mode;
>> @@ -27,17 +39,61 @@ void generic_fillattr(struct inode *inode, struct kstat 
>> *stat)
>>      stat->uid = inode->i_uid;
>>      stat->gid = inode->i_gid;
>>      stat->rdev = inode->i_rdev;
>> -    stat->size = i_size_read(inode);
>> -    stat->atime = inode->i_atime;
>>      stat->mtime = inode->i_mtime;
>>      stat->ctime = inode->i_ctime;
>> -    stat->blksize = (1 << inode->i_blkbits);
>> +    stat->size = i_size_read(inode);
>>      stat->blocks = inode->i_blocks;
>> -}
>> +    stat->blksize = (1 << inode->i_blkbits);
>> 
>> +    stat->result_mask |= XSTAT_BASIC_STATS & ~XSTAT_RDEV;
>> +    if (IS_NOATIME(inode))
>> +            stat->result_mask &= ~XSTAT_ATIME;
>> +    else
>> +            stat->atime = inode->i_atime;
>> +
>> +    if (S_ISREG(stat->mode) && stat->nlink == 0)
>> +            stat->information |= XSTAT_INFO_TEMPORARY;
>> +    if (IS_AUTOMOUNT(inode))
>> +            stat->information |= XSTAT_INFO_AUTOMOUNT;
>> +    if (IS_POSIXACL(inode))
>> +            stat->information |= XSTAT_INFO_HAS_ACL;
>> +
>> +    /* if unset, assume 1s granularity */
>> +    stat->tv_granularity = sb->s_time_gran ?: 1000000000U;
>> +
>> +    if (unlikely(S_ISBLK(stat->mode) || S_ISCHR(stat->mode)))
>> +            stat->result_mask |= XSTAT_RDEV;
>> +
>> +    x  = ((u32*)&stat->volume_id)[0] = ((u32*)&sb->s_volume_id)[0];
>> +    x |= ((u32*)&stat->volume_id)[1] = ((u32*)&sb->s_volume_id)[1];
>> +    x |= ((u32*)&stat->volume_id)[2] = ((u32*)&sb->s_volume_id)[2];
>> +    x |= ((u32*)&stat->volume_id)[3] = ((u32*)&sb->s_volume_id)[3];
>> +    if (x)
>> +            stat->result_mask |= XSTAT_VOLUME_ID;
>> +}
>> EXPORT_SYMBOL(generic_fillattr);
>> 
>> -int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat 
>> *stat)
>> +/**
>> + * vfs_xgetattr - Get the basic and extra attributes of a file
>> + * @mnt: The mountpoint to which the dentry belongs
>> + * @dentry: The file of interest
>> + * @stat: Where to return the statistics
>> + *
>> + * Ask the filesystem for a file's attributes.  The caller must have preset
>> + * stat->request_mask and stat->query_flags to indicate what they want.
>> + *
>> + * If the file is remote, the filesystem can be forced to update the 
>> attributes
>> + * from the backing store by passing AT_FORCE_ATTR_SYNC in query_flags.
>> + *
>> + * Bits must have been set in stat->request_mask to indicate which 
>> attributes
>> + * the caller wants retrieving.  Any such attribute not requested may be
>> + * returned anyway, but the value may be approximate, and, if remote, may 
>> not
>> + * have been synchronised with the server.
>> + *
>> + * 0 will be returned on success, and a -ve error code if unsuccessful.
>> + */
>> +int vfs_xgetattr(struct vfsmount *mnt, struct dentry *dentry,
>> +             struct kstat *stat)
>> {
>>      struct inode *inode = dentry->d_inode;
>>      int retval;
>> @@ -46,64 +102,184 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry 
>> *dentry, struct kstat *stat)
>>      if (retval)
>>              return retval;
>> 
>> +    stat->result_mask = 0;
>> +    stat->information = 0;
>> +    stat->ioc_flags = 0;
>>      if (inode->i_op->getattr)
>>              return inode->i_op->getattr(mnt, dentry, stat);
>> 
>>      generic_fillattr(inode, stat);
>>      return 0;
>> }
>> +EXPORT_SYMBOL(vfs_xgetattr);
>> 
>> +/**
>> + * vfs_getattr - Get the basic attributes of a file
>> + * @mnt: The mountpoint to which the dentry belongs
>> + * @dentry: The file of interest
>> + * @stat: Where to return the statistics
>> + *
>> + * Ask the filesystem for a file's attributes.  If remote, the filesystem 
>> isn't
>> + * forced to update its files from the backing store.  Only the basic set of
>> + * attributes will be retrieved; anyone wanting more must use 
>> vfs_getxattr(),
>> + * as must anyone who wants to force attributes to be sync'd with the 
>> server.
>> + *
>> + * 0 will be returned on success, and a -ve error code if unsuccessful.
>> + */
>> +int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat 
>> *stat)
>> +{
>> +    stat->query_flags = 0;
>> +    stat->request_mask = XSTAT_BASIC_STATS;
>> +    return vfs_xgetattr(mnt, dentry, stat);
>> +}
>> EXPORT_SYMBOL(vfs_getattr);
>> 
>> -int vfs_fstat(unsigned int fd, struct kstat *stat)
>> +/**
>> + * vfs_fxstat - Get basic and extra attributes by file descriptor
>> + * @fd: The file descriptor refering to the file of interest
>> + * @stat: The result structure to fill in.
>> + *
>> + * This function is a wrapper around vfs_xgetattr().  The main difference is
>> + * that it uses a file descriptor to determine the file location.
>> + *
>> + * The caller must have preset stat->query_flags and stat->request_mask as 
>> for
>> + * vfs_xgetattr().
>> + *
>> + * 0 will be returned on success, and a -ve error code if unsuccessful.
>> + */
>> +int vfs_fxstat(unsigned int fd, struct kstat *stat)
>> {
>>      struct file *f = fget(fd);
>>      int error = -EBADF;
>> 
>> +    if (stat->query_flags & ~KSTAT_QUERY_FLAGS)
>> +            return -EINVAL;
>>      if (f) {
>> -            error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat);
>> +            error = vfs_xgetattr(f->f_path.mnt, f->f_path.dentry, stat);
>>              fput(f);
>>      }
>>      return error;
>> }
>> +EXPORT_SYMBOL(vfs_fxstat);
>> +
>> +/**
>> + * vfs_fstat - Get basic attributes by file descriptor
>> + * @fd: The file descriptor refering to the file of interest
>> + * @stat: The result structure to fill in.
>> + *
>> + * This function is a wrapper around vfs_getattr().  The main difference is
>> + * that it uses a file descriptor to determine the file location.
>> + *
>> + * 0 will be returned on success, and a -ve error code if unsuccessful.
>> + */
>> +int vfs_fstat(unsigned int fd, struct kstat *stat)
>> +{
>> +    stat->query_flags = 0;
>> +    stat->request_mask = XSTAT_BASIC_STATS;
>> +    return vfs_fxstat(fd, stat);
>> +}
>> EXPORT_SYMBOL(vfs_fstat);
>> 
>> -int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
>> -            int flag)
>> +/**
>> + * vfs_xstat - Get basic and extra attributes by filename
>> + * @dfd: A file descriptor representing the base dir for a relative filename
>> + * @filename: The name of the file of interest
>> + * @flags: Flags to control the query
>> + * @stat: The result structure to fill in.
>> + *
>> + * This function is a wrapper around vfs_xgetattr().  The main difference is
>> + * that it uses a filename and base directory to determine the file 
>> location.
>> + * Additionally, the addition of AT_SYMLINK_NOFOLLOW to flags will prevent a
>> + * symlink at the given name from being referenced.
>> + *
>> + * The caller must have preset stat->request_mask as for vfs_xgetattr().  
>> The
>> + * flags are also used to load up stat->query_flags.
>> + *
>> + * 0 will be returned on success, and a -ve error code if unsuccessful.
>> + */
>> +int vfs_xstat(int dfd, const char __user *filename, int flags,
>> +          struct kstat *stat)
>> {
>>      struct path path;
>> -    int error = -EINVAL;
>> -    int lookup_flags = 0;
>> +    int error, lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
>> 
>> -    if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
>> -                  AT_EMPTY_PATH)) != 0)
>> -            goto out;
>> +    if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
>> +                  AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0)
>> +            return -EINVAL;
>> 
>> -    if (!(flag & AT_SYMLINK_NOFOLLOW))
>> -            lookup_flags |= LOOKUP_FOLLOW;
>> -    if (flag & AT_EMPTY_PATH)
>> +    if (flags & AT_SYMLINK_NOFOLLOW)
>> +            lookup_flags &= ~LOOKUP_FOLLOW;
>> +    if (flags & AT_NO_AUTOMOUNT)
>> +            lookup_flags &= ~LOOKUP_AUTOMOUNT;
>> +    if (flags & AT_EMPTY_PATH)
>>              lookup_flags |= LOOKUP_EMPTY;
>> 
>> +    stat->query_flags = flags & KSTAT_QUERY_FLAGS;
>>      error = user_path_at(dfd, filename, lookup_flags, &path);
>> -    if (error)
>> -            goto out;
>> -
>> -    error = vfs_getattr(path.mnt, path.dentry, stat);
>> -    path_put(&path);
>> -out:
>> +    if (!error) {
>> +            error = vfs_xgetattr(path.mnt, path.dentry, stat);
>> +            path_put(&path);
>> +    }
>>      return error;
>> }
>> +EXPORT_SYMBOL(vfs_xstat);
>> +
>> +/**
>> + * vfs_fstatat - Get basic attributes by filename
>> + * @dfd: A file descriptor representing the base dir for a relative filename
>> + * @filename: The name of the file of interest
>> + * @flags: Flags to control the query
>> + * @stat: The result structure to fill in.
>> + *
>> + * This function is a wrapper around vfs_xstat().  The difference is that it
>> + * preselects basic stats only.  The flags are used to load up
>> + * stat->query_flags in addition to indicating symlink handling during path
>> + * resolution.
>> + *
>> + * 0 will be returned on success, and a -ve error code if unsuccessful.
>> + */
>> +int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
>> +            int flags)
>> +{
>> +    stat->request_mask = XSTAT_BASIC_STATS;
>> +    return vfs_xstat(dfd, filename, flags, stat);
>> +}
>> EXPORT_SYMBOL(vfs_fstatat);
>> 
>> -int vfs_stat(const char __user *name, struct kstat *stat)
>> +/**
>> + * vfs_stat - Get basic attributes by filename
>> + * @filename: The name of the file of interest
>> + * @stat: The result structure to fill in.
>> + *
>> + * This function is a wrapper around vfs_xstat().  The difference is that it
>> + * preselects basic stats only, terminal symlinks are followed regardless 
>> and a
>> + * remote filesystem can't be forced to query the server.  If such is 
>> desired,
>> + * vfs_xstat() should be used instead.
>> + *
>> + * 0 will be returned on success, and a -ve error code if unsuccessful.
>> + */
>> +int vfs_stat(const char __user *filename, struct kstat *stat)
>> {
>> -    return vfs_fstatat(AT_FDCWD, name, stat, 0);
>> +    stat->request_mask = XSTAT_BASIC_STATS;
>> +    return vfs_xstat(AT_FDCWD, filename, 0, stat);
>> }
>> EXPORT_SYMBOL(vfs_stat);
>> 
>> +/**
>> + * vfs_stat - Get basic attributes by filename, without following terminal 
>> symlink
>> + * @filename: The name of the file of interest
>> + * @stat: The result structure to fill in.
>> + *
>> + * This function is a wrapper around vfs_xstat().  The difference is that it
>> + * preselects basic stats only, terminal symlinks are note followed 
>> regardless
>> + * and a remote filesystem can't be forced to query the server.  If such is
>> + * desired, vfs_xstat() should be used instead.
>> + *
>> + * 0 will be returned on success, and a -ve error code if unsuccessful.
>> + */
>> int vfs_lstat(const char __user *name, struct kstat *stat)
>> {
>> -    return vfs_fstatat(AT_FDCWD, name, stat, AT_SYMLINK_NOFOLLOW);
>> +    return vfs_xstat(AT_FDCWD, name, AT_SYMLINK_NOFOLLOW, stat);
>> }
>> EXPORT_SYMBOL(vfs_lstat);
>> 
>> @@ -118,7 +294,7 @@ static int cp_old_stat(struct kstat *stat, struct 
>> __old_kernel_stat __user * sta
>> {
>>      static int warncount = 5;
>>      struct __old_kernel_stat tmp;
>> -    
>> +
>>      if (warncount > 0) {
>>              warncount--;
>>              printk(KERN_WARNING "VFS: Warning: %s using old stat() call. 
>> Recompile your binary.\n",
>> @@ -143,7 +319,7 @@ static int cp_old_stat(struct kstat *stat, struct 
>> __old_kernel_stat __user * sta
>> #if BITS_PER_LONG == 32
>>      if (stat->size > MAX_NON_LFS)
>>              return -EOVERFLOW;
>> -#endif      
>> +#endif
>>      tmp.st_size = stat->size;
>>      tmp.st_atime = stat->atime.tv_sec;
>>      tmp.st_mtime = stat->mtime.tv_sec;
>> @@ -225,7 +401,7 @@ static int cp_new_stat(struct kstat *stat, struct stat 
>> __user *statbuf)
>> #if BITS_PER_LONG == 32
>>      if (stat->size > MAX_NON_LFS)
>>              return -EOVERFLOW;
>> -#endif      
>> +#endif
>>      tmp.st_size = stat->size;
>>      tmp.st_atime = stat->atime.tv_sec;
>>      tmp.st_mtime = stat->mtime.tv_sec;
>> @@ -412,6 +588,122 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user 
>> *, filename,
>> }
>> #endif /* __ARCH_WANT_STAT64 */
>> 
>> +/*
>> + * Get the xstat parameters if supplied
>> + */
>> +static int xstat_get_params(unsigned int mask, struct xstat __user *buffer,
>> +                        struct kstat *stat)
>> +{
>> +    memset(stat, 0xde, sizeof(*stat));      // DEBUGGING
>> +
>> +    if (!access_ok(VERIFY_WRITE, buffer, sizeof(*buffer)))
>> +            return -EFAULT;
>> +
>> +    stat->request_mask = mask & XSTAT_ALL_STATS;
>> +    stat->result_mask = 0;
>> +    return 0;
>> +}
>> +
>> +/*
>> + * Set the xstat results.
>> + *
>> + * If the buffer size was 0, we just return the size of the buffer needed to
>> + * return the full result.
>> + *
>> + * If bufsize indicates a buffer of insufficient size to hold the full 
>> result,
>> + * we return -E2BIG.
>> + *
>> + * Otherwise we copy the extended stats to userspace and return the amount 
>> of
>> + * data written into the buffer (or -EFAULT).
>> + */
>> +static long xstat_set_result(struct kstat *stat, struct xstat __user 
>> *buffer)
>> +{
>> +    u32 mask = stat->result_mask, gran = stat->tv_granularity;
>> +
>> +#define __put_timestamp(kts, uts) (                                 \
>> +            __put_user(kts.tv_sec,  uts.tv_sec              ) ||    \
>> +            __put_user(kts.tv_nsec, uts.tv_nsec             ) ||    \
>> +            __put_user(gran,        uts.tv_granularity      ))
>> +
>> +    /* clear out anything we're not returning */
>> +    if (!(mask & XSTAT_IOC_FLAGS))
>> +            stat->ioc_flags = 0;
>> +    if (!(mask & XSTAT_BTIME))
>> +            memset(&stat->btime, 0, sizeof(stat->btime));
>> +    if (!(mask & XSTAT_GEN))
>> +            stat->gen = 0;
>> +    if (!(mask & XSTAT_VERSION))
>> +            stat->version = 0;
>> +    if (!(mask & XSTAT_VOLUME_ID))
>> +            memset(&stat->volume_id, 0, sizeof(stat->volume_id));
>> +    
>> +    /* transfer the results */
>> +    if (__put_user(mask,                    &buffer->st_mask        ) ||
>> +        __put_user(stat->mode,              &buffer->st_mode        ) ||
>> +        __put_user(stat->nlink,             &buffer->st_nlink       ) ||
>> +        __put_user(stat->uid,               &buffer->st_uid         ) ||
>> +        __put_user(stat->gid,               &buffer->st_gid         ) ||
>> +        __put_user(stat->information,       &buffer->st_information ) ||
>> +        __put_user(stat->ioc_flags,         &buffer->st_ioc_flags   ) ||
>> +        __put_user(stat->blksize,           &buffer->st_blksize     ) ||
>> +        __put_user(MAJOR(stat->rdev),       &buffer->st_rdev.major  ) ||
>> +        __put_user(MINOR(stat->rdev),       &buffer->st_rdev.minor  ) ||
>> +        __put_user(MAJOR(stat->dev),        &buffer->st_dev.major   ) ||
>> +        __put_user(MINOR(stat->dev),        &buffer->st_dev.minor   ) ||
>> +        __put_timestamp(stat->atime,        &buffer->st_atime       ) ||
>> +        __put_timestamp(stat->btime,        &buffer->st_btime       ) ||
>> +        __put_timestamp(stat->ctime,        &buffer->st_ctime       ) ||
>> +        __put_timestamp(stat->mtime,        &buffer->st_mtime       ) ||
>> +        __put_user(stat->ino,               &buffer->st_ino         ) ||
>> +        __put_user(stat->size,              &buffer->st_size        ) ||
>> +        __put_user(stat->blocks,            &buffer->st_blocks      ) ||
>> +        __put_user(stat->gen,               &buffer->st_gen         ) ||
>> +        __put_user(stat->version,           &buffer->st_version     ) ||
>> +        __copy_to_user(&buffer->st_volume_id, &stat->volume_id,
>> +                       sizeof(buffer->st_volume_id)                 ) ||
>> +        __clear_user(&buffer->__spares, sizeof(buffer->__spares)))
>> +            return -EFAULT;
>> +    return 0;
>> +}
>> +
>> +/*
>> + * System call to get extended stats by path
>> + */
>> +SYSCALL_DEFINE5(xstat,
>> +            int, dfd, const char __user *, filename, unsigned, flags,
>> +            unsigned int, mask, struct xstat __user *, buffer)
>> +{
>> +    struct kstat stat;
>> +    int error;
>> +
>> +    error = xstat_get_params(mask, buffer, &stat);
>> +    if (error != 0)
>> +            return error;
>> +    error = vfs_xstat(dfd, filename, flags, &stat);
>> +    if (error)
>> +            return error;
>> +    return xstat_set_result(&stat, buffer);
>> +}
>> +
>> +/*
>> + * System call to get extended stats by file descriptor
>> + */
>> +SYSCALL_DEFINE4(fxstat, unsigned int, fd, unsigned int, flags,
>> +            unsigned int, mask, struct xstat __user *, buffer)
>> +{
>> +    struct kstat stat;
>> +    int error;
>> +
>> +    error = xstat_get_params(mask, buffer, &stat);
>> +    if (error < 0)
>> +            return error;
>> +    stat.query_flags = flags;
>> +    error = vfs_fxstat(fd, &stat);
>> +    if (error)
>> +            return error;
>> +    return xstat_set_result(&stat, buffer);
>> +}
>> +
>> /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */
>> void __inode_add_bytes(struct inode *inode, loff_t bytes)
>> {
>> diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
>> index f550f89..faa9e5d 100644
>> --- a/include/linux/fcntl.h
>> +++ b/include/linux/fcntl.h
>> @@ -47,6 +47,7 @@
>> #define AT_SYMLINK_FOLLOW    0x400   /* Follow symbolic links.  */
>> #define AT_NO_AUTOMOUNT              0x800   /* Suppress terminal automount 
>> traversal */
>> #define AT_EMPTY_PATH                0x1000  /* Allow empty relative 
>> pathname */
>> +#define AT_FORCE_ATTR_SYNC  0x2000  /* Force the attributes to be sync'd 
>> with the server */
>> 
>> #ifdef __KERNEL__
>> 
>> diff --git a/include/linux/fs.h b/include/linux/fs.h
>> index 8de6755..ec6c62e 100644
>> --- a/include/linux/fs.h
>> +++ b/include/linux/fs.h
>> @@ -1467,6 +1467,7 @@ struct super_block {
>> 
>>      char s_id[32];                          /* Informational name */
>>      u8 s_uuid[16];                          /* UUID */
>> +    unsigned char           s_volume_id[16]; /* Volume identifier */
>> 
>>      void                    *s_fs_info;     /* Filesystem private info */
>>      unsigned int            s_max_links;
>> @@ -2470,6 +2471,7 @@ extern const struct inode_operations 
>> page_symlink_inode_operations;
>> extern int generic_readlink(struct dentry *, char __user *, int);
>> extern void generic_fillattr(struct inode *, struct kstat *);
>> extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
>> +extern int vfs_xgetattr(struct vfsmount *, struct dentry *, struct kstat *);
>> void __inode_add_bytes(struct inode *inode, loff_t bytes);
>> void inode_add_bytes(struct inode *inode, loff_t bytes);
>> void inode_sub_bytes(struct inode *inode, loff_t bytes);
>> @@ -2482,6 +2484,8 @@ extern int vfs_stat(const char __user *, struct kstat 
>> *);
>> extern int vfs_lstat(const char __user *, struct kstat *);
>> extern int vfs_fstat(unsigned int, struct kstat *);
>> extern int vfs_fstatat(int , const char __user *, struct kstat *, int);
>> +extern int vfs_xstat(int, const char __user *, int, struct kstat *);
>> +extern int vfs_xfstat(unsigned int, struct kstat *);
>> 
>> extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
>>                  unsigned long arg);
>> diff --git a/include/linux/stat.h b/include/linux/stat.h
>> index 611c398..0ff561a 100644
>> --- a/include/linux/stat.h
>> +++ b/include/linux/stat.h
>> @@ -3,6 +3,7 @@
>> 
>> #ifdef __KERNEL__
>> 
>> +#include <linux/types.h>
>> #include <asm/stat.h>
>> 
>> #endif
>> @@ -46,6 +47,117 @@
>> 
>> #endif
>> 
>> +/*
>> + * Query request/result mask
>> + *
>> + * Bits should be set in request_mask to request particular items when 
>> calling
>> + * xstat() or fxstat().
>> + *
>> + * The bits in st_mask may or may not be set upon return, in part depending 
>> on
>> + * what was set in the mask argument:
>> + *
>> + * - if not available at all, the bit will be cleared before returning and 
>> the
>> + *   field will be cleared; otherwise,
>> + *
>> + * - if AT_FORCE_ATTR_SYNC is set, then the datum will be synchronised to 
>> the
>> + *   server and the field and bit will be set on return; otherwise,
>> + *
>> + * - if explicitly requested, the datum will be synchronised to a server or
>> + *   other medium if out of date before being returned, and the bit will be 
>> set
>> + *   on return; otherwise,
>> + *
>> + * - if not requested, but available in approximate form without any 
>> effort, it
>> + *   will be filled in anyway, and the bit will be set upon return (it might
>> + *   not be up to date, however, and no attempt will be made to synchronise 
>> the
>> + *   internal state first); otherwise,
>> + *
>> + * - the field and the bit will be cleared before returning.
>> + *
>> + * Items in XSTAT_BASIC_STATS may be marked unavailable on return, but they
>> + * will have a value installed for compatibility purposes so that stat() and
>> + * co. can be emulated in userspace.
>> + */
>> +#define XSTAT_MODE          0x00000001U     /* want/got st_mode */
>> +#define XSTAT_NLINK         0x00000002U     /* want/got st_nlink */
>> +#define XSTAT_UID           0x00000004U     /* want/got st_uid */
>> +#define XSTAT_GID           0x00000008U     /* want/got st_gid */
>> +#define XSTAT_RDEV          0x00000010U     /* want/got st_rdev */
>> +#define XSTAT_ATIME         0x00000020U     /* want/got st_atime */
>> +#define XSTAT_MTIME         0x00000040U     /* want/got st_mtime */
>> +#define XSTAT_CTIME         0x00000080U     /* want/got st_ctime */
>> +#define XSTAT_INO           0x00000100U     /* want/got st_ino */
>> +#define XSTAT_SIZE          0x00000200U     /* want/got st_size */
>> +#define XSTAT_BLOCKS                0x00000400U     /* want/got st_blocks */
>> +#define XSTAT_BASIC_STATS   0x000007ffU     /* the stuff in the normal stat 
>> struct */
>> +#define XSTAT_IOC_FLAGS             0x00000800U     /* want/got 
>> FS_IOC_GETFLAGS */
>> +#define XSTAT_BTIME         0x00001000U     /* want/got st_btime */
>> +#define XSTAT_GEN           0x00002000U     /* want/got st_gen */
>> +#define XSTAT_VERSION               0x00004000U     /* want/got st_version 
>> */
>> +#define XSTAT_VOLUME_ID             0x00008000U     /* want/got 
>> st_volume_id */
>> +#define XSTAT_ALL_STATS             0x0000ffffU     /* all supported stats 
>> */
>> +
>> +/*
>> + * Extended stat structures
>> + */
>> +struct xstat_dev {
>> +    uint32_t                major, minor;
>> +};
>> +
>> +struct xstat_time {
>> +    int64_t                 tv_sec;
>> +    uint32_t                tv_nsec;
>> +    uint32_t                tv_granularity; /* time granularity (in nS) */
>> +};
>> +
>> +struct xstat {
>> +    uint32_t                st_mask;        /* what results were written */
>> +    uint32_t                st_mode;        /* file mode */
>> +    uint32_t                st_nlink;       /* number of hard links */
>> +    uint32_t                st_uid;         /* user ID of owner */
>> +    uint32_t                st_gid;         /* group ID of owner */
>> +    uint32_t                st_information; /* information about the file */
>> +    uint32_t                st_ioc_flags;   /* as FS_IOC_GETFLAGS */
>> +    uint32_t                st_blksize;     /* optimal size for filesystem 
>> I/O */
>> +    struct xstat_dev        st_rdev;        /* device ID of special file */
>> +    struct xstat_dev        st_dev;         /* ID of device containing file 
>> */
>> +    struct xstat_time       st_atime;       /* last access time */
>> +    struct xstat_time       st_btime;       /* file creation time */
>> +    struct xstat_time       st_ctime;       /* last attribute change time */
>> +    struct xstat_time       st_mtime;       /* last data modification time 
>> */
>> +    uint64_t                st_ino;         /* inode number */
>> +    uint64_t                st_size;        /* file size */
>> +    uint64_t                st_blocks;      /* number of 512-byte blocks 
>> allocated */
>> +    uint64_t                st_gen;         /* inode generation number */
>> +    uint64_t                st_version;     /* data version number */
>> +    uint8_t                 st_volume_id[16]; /* volume identifier */
>> +    uint64_t                __spares[11];   /* spare space for future 
>> expansion */
>> +};
>> +
>> +/*
>> + * Flags to be found in st_information
>> + *
>> + * These give information about the features or the state of a file that 
>> might
>> + * be of use to ordinary userspace programs such as GUIs or ls rather than
>> + * specialised tools.
>> + *
>> + * Additional information may be found in st_ioc_flags and we try not to
>> + * overlap with it.
>> + */
>> +#define XSTAT_INFO_ENCRYPTED                0x00000001U /* File is 
>> encrypted */
>> +#define XSTAT_INFO_TEMPORARY                0x00000002U /* File is 
>> temporary (NTFS/CIFS) */
>> +#define XSTAT_INFO_FABRICATED               0x00000004U /* File was made up 
>> by filesystem */
>> +#define XSTAT_INFO_KERNEL_API               0x00000008U /* File is kernel 
>> API (eg: procfs/sysfs) */
>> +#define XSTAT_INFO_REMOTE           0x00000010U /* File is remote */
>> +#define XSTAT_INFO_OFFLINE          0x00000020U /* File is offline (CIFS) */
>> +#define XSTAT_INFO_AUTOMOUNT                0x00000040U /* Dir is automount 
>> trigger */
>> +#define XSTAT_INFO_AUTODIR          0x00000080U /* Dir provides unlisted 
>> automounts */
>> +#define XSTAT_INFO_NONSYSTEM_OWNERSHIP      0x00000100U /* File has 
>> non-system ownership details */
>> +#define XSTAT_INFO_HAS_ACL          0x00000200U /* File has an ACL of some 
>> sort */
>> +#define XSTAT_INFO_REPARSE_POINT    0x00000400U /* File is reparse point 
>> (NTFS/CIFS) */
>> +#define XSTAT_INFO_HIDDEN           0x00000800U /* File is marked hidden 
>> (DOS+) */
>> +#define XSTAT_INFO_SYSTEM           0x00001000U /* File is marked system 
>> (DOS+) */
>> +#define XSTAT_INFO_ARCHIVE          0x00002000U /* File is marked archive 
>> (DOS+) */
>> +
>> #ifdef __KERNEL__
>> #define S_IRWXUGO    (S_IRWXU|S_IRWXG|S_IRWXO)
>> #define S_IALLUGO    (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
>> @@ -60,6 +172,12 @@
>> #include <linux/time.h>
>> 
>> struct kstat {
>> +    u32             query_flags;            /* operational flags */
>> +#define KSTAT_QUERY_FLAGS (AT_FORCE_ATTR_SYNC)
>> +    u32             request_mask;           /* what fields the user asked 
>> for */
>> +    u32             result_mask;            /* what fields the user got */
>> +    u32             information;
>> +    u32             ioc_flags;              /* inode flags 
>> (FS_IOC_GETFLAGS) */
>>      u64             ino;
>>      dev_t           dev;
>>      umode_t         mode;
>> @@ -67,14 +185,18 @@ struct kstat {
>>      uid_t           uid;
>>      gid_t           gid;
>>      dev_t           rdev;
>> +    unsigned int    tv_granularity;         /* granularity of times (in nS) 
>> */
>>      loff_t          size;
>> -    struct timespec  atime;
>> +    struct timespec atime;
>>      struct timespec mtime;
>>      struct timespec ctime;
>> +    struct timespec btime;                  /* file creation time */
>>      unsigned long   blksize;
>>      unsigned long long      blocks;
>> +    u64             gen;                    /* inode generation */
>> +    u64             version;                /* data version */
>> +    unsigned char   volume_id[16];          /* volume identifier */
>> };
>> 
>> #endif
>> -
>> #endif
>> diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
>> index 3de3acb..ff9f8d9 100644
>> --- a/include/linux/syscalls.h
>> +++ b/include/linux/syscalls.h
>> @@ -45,6 +45,8 @@ struct shmid_ds;
>> struct sockaddr;
>> struct stat;
>> struct stat64;
>> +struct xstat_parameters;
>> +struct xstat;
>> struct statfs;
>> struct statfs64;
>> struct __sysctl_args;
>> @@ -858,4 +860,9 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
>>                                    unsigned long riovcnt,
>>                                    unsigned long flags);
>> 
>> +asmlinkage long sys_xstat(int dfd, const char __user *path, unsigned flags,
>> +                      unsigned mask, struct xstat __user *buffer);
>> +asmlinkage long sys_fxstat(unsigned fd, unsigned flags,
>> +                       unsigned mask, struct xstat __user *buffer);
>> +
>> #endif
>> 
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
>> the body of a message to majord...@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


Cheers, Andreas





-- 
nautilus-list mailing list
nautilus-list@gnome.org
http://mail.gnome.org/mailman/listinfo/nautilus-list

Reply via email to