All of lore.kernel.org
 help / color / mirror / Atom feed
From: Steve French <smfrench@gmail.com>
To: unlisted-recipients:; (no To-header on input)
Cc: linux-afs@vger.kernel.org,
	"linux-nfs@vger.kernel.org" <linux-nfs@vger.kernel.org>,
	"linux-cifs@vger.kernel.org" <linux-cifs@vger.kernel.org>,
	samba-technical <samba-technical@lists.samba.org>,
	LKML <linux-kernel@vger.kernel.org>,
	linux-fsdevel <linux-fsdevel@vger.kernel.org>,
	"linux-ext4@vger.kernel.org" <linux-ext4@vger.kernel.org>
Subject: Re: [PATCH 07/12] statx: CIFS: Return enhanced attributes
Date: Tue, 24 Nov 2015 11:34:52 -0600	[thread overview]
Message-ID: <CAH2r5mt2SZPD+THkj12qxoZ9=F-NC_ZuhdoJRy0pQe5S+bUo3w@mail.gmail.com> (raw)
In-Reply-To: <20151120145548.18930.11614.stgit@warthog.procyon.org.uk>

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

WARNING: multiple messages have this Message-ID (diff)
From: Steve French <smfrench@gmail.com>
To: unlisted-recipients:; (no To-header on input)@mail.corp.redhat.com
Cc: linux-afs@vger.kernel.org,
	"linux-nfs@vger.kernel.org" <linux-nfs@vger.kernel.org>,
	"linux-cifs@vger.kernel.org" <linux-cifs@vger.kernel.org>,
	samba-technical <samba-technical@lists.samba.org>,
	LKML <linux-kernel@vger.kernel.org>,
	linux-fsdevel <linux-fsdevel@vger.kernel.org>,
	"linux-ext4@vger.kernel.org" <linux-ext4@vger.kernel.org>
Subject: Re: [PATCH 07/12] statx: CIFS: Return enhanced attributes
Date: Tue, 24 Nov 2015 11:34:52 -0600	[thread overview]
Message-ID: <CAH2r5mt2SZPD+THkj12qxoZ9=F-NC_ZuhdoJRy0pQe5S+bUo3w@mail.gmail.com> (raw)
In-Reply-To: <20151120145548.18930.11614.stgit@warthog.procyon.org.uk>

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

  parent reply	other threads:[~2015-11-24 17:34 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-20 14:54 [RFC][PATCH 00/12] Enhanced file stat system call David Howells
2015-11-20 14:54 ` [PATCH 01/12] Ext4: Fix extended timestamp encoding and decoding David Howells
     [not found]   ` <20151120145434.18930.89755.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2015-11-24 17:37     ` Andreas Dilger
2015-11-24 17:37       ` Andreas Dilger
2015-11-24 19:36   ` Theodore Ts'o
     [not found]     ` <20151124193646.GA3482-AKGzg7BKzIDYtjvyW6yDsg@public.gmane.org>
2015-11-24 20:10       ` Arnd Bergmann
2015-11-24 20:10         ` Arnd Bergmann
2015-11-29  2:45         ` Theodore Ts'o
2015-11-29  2:45           ` Theodore Ts'o
     [not found]           ` <20151129024555.GA31968-AKGzg7BKzIDYtjvyW6yDsg@public.gmane.org>
2015-11-29 21:30             ` Arnd Bergmann
2015-11-29 21:30               ` Arnd Bergmann
2015-11-30 14:16               ` Theodore Ts'o
     [not found]                 ` <20151130141605.GA4316-AKGzg7BKzIDYtjvyW6yDsg@public.gmane.org>
2015-11-30 14:37                   ` Arnd Bergmann
2015-11-30 14:37                     ` Arnd Bergmann
2015-11-30 14:46                 ` Elmar Stellnberger
2015-11-26 15:28       ` David Howells
2015-11-26 15:28         ` David Howells
2015-11-20 14:54 ` [PATCH 02/12] statx: Provide IOC flags for Windows fs attributes David Howells
     [not found]   ` <20151120145447.18930.5308.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2015-11-24 19:52     ` Theodore Ts'o
2015-11-24 19:52       ` Theodore Ts'o
2015-11-26 15:35   ` David Howells
     [not found]   ` <7976.1448552129-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2015-11-26 16:01     ` David Howells
2015-11-26 16:01       ` David Howells
2015-11-26 22:10     ` Andreas Dilger
2015-11-26 22:10       ` Andreas Dilger
2015-11-20 14:54 ` [PATCH 03/12] statx: Add a system call to make enhanced file info available David Howells
     [not found]   ` <20151120145457.18930.79678.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2015-11-24 20:21     ` Dave Chinner
2015-11-24 20:21       ` Dave Chinner
2015-12-04 12:06     ` Pavel Machek
2015-12-04 12:06       ` Pavel Machek
2015-12-21 23:21   ` David Howells
2015-11-20 14:55 ` [PATCH 04/12] statx: AFS: Return enhanced file attributes David Howells
2015-11-20 14:55 ` [PATCH 05/12] statx: Ext4: " David Howells
2015-11-20 14:55 ` [PATCH 06/12] statx: NFS: " David Howells
2015-11-20 14:55 ` [PATCH 07/12] statx: CIFS: Return enhanced attributes David Howells
2015-11-24 17:33   ` Steve French
2015-11-24 17:34   ` Steve French [this message]
2015-11-24 17:34     ` Steve French
2015-11-20 14:56 ` [PATCH 08/12] fsinfo: Add a system call to make enhanced filesystem info available David Howells
2015-11-20 14:56 ` [PATCH 09/12] fsinfo: Ext4: Return information through the filesystem info syscall David Howells
2015-11-20 14:56 ` [PATCH 10/12] fsinfo: AFS: " David Howells
2015-11-20 14:56 ` [PATCH 11/12] fsinfo: NFS: " David Howells
     [not found] ` <20151120145422.18930.72662.stgit-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2015-11-20 14:56   ` [PATCH 12/12] fsinfo: CIFS: " David Howells
2015-11-20 14:56     ` David Howells
2015-11-24  8:11   ` [RFC][PATCH 00/12] Enhanced file stat system call Christoph Hellwig
2015-11-24  8:11     ` Christoph Hellwig
2015-11-20 16:19 ` Martin Steigerwald
2015-11-24  8:13   ` Christoph Hellwig
2015-11-24  8:48     ` Martin Steigerwald
2015-11-24  8:50       ` Christoph Hellwig
2015-11-20 16:28 ` David Howells
2015-11-20 16:28   ` David Howells
2015-11-20 16:35   ` Martin Steigerwald
     [not found]   ` <4495.1448036915-S6HVgzuS8uM4Awkfq6JHfwNdhmdF6hFW@public.gmane.org>
2015-11-25 17:51     ` J. Bruce Fields
2015-11-25 17:51       ` J. Bruce Fields
     [not found]       ` <20151125175153.GA30335-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2015-11-25 19:30         ` Andreas Dilger
2015-11-25 19:30           ` Andreas Dilger
2015-11-20 16:50 ` Casey Schaufler
     [not found]   ` <564F4F4E.8060603-iSGtlc1asvQWG2LlvL+J4A@public.gmane.org>
2015-11-24  8:15     ` Christoph Hellwig
2015-11-24  8:15       ` Christoph Hellwig
2015-11-24 14:43       ` Casey Schaufler
2015-11-24 16:28   ` Andreas Dilger
2015-11-26 15:19 ` David Howells
2015-11-26 22:06   ` Andreas Dilger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAH2r5mt2SZPD+THkj12qxoZ9=F-NC_ZuhdoJRy0pQe5S+bUo3w@mail.gmail.com' \
    --to=smfrench@gmail.com \
    --cc=linux-afs@vger.kernel.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=linux-ext4@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=samba-technical@lists.samba.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.