diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index d1389bb..021e327 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -56,9 +56,9 @@ extern int cifs_rmdir(struct inode *, struct dentry *);
 extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
 		       struct dentry *);
 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_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int cifs_setattr(struct dentry *, struct iattr *);
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 4ff6313..d3567da 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -621,11 +621,15 @@ struct cifsInodeInfo {
 	/* BB add in lists for dirty pages i.e. write caching info for oplock */
 	struct list_head openFileList;
 	__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
-	bool clientCanCacheRead;	/* read oplock */
-	bool clientCanCacheAll;		/* read and writebehind oplock */
-	bool delete_pending;		/* DELETE_ON_CLOSE is set */
-	bool invalid_mapping;		/* pagecache is invalid */
+	bool clientCanCacheRead:1;	/* read oplock */
+	bool clientCanCacheAll:1;	/* read and writebehind oplock */
+	bool delete_pending:1;		/* DELETE_ON_CLOSE is set */
+	bool invalid_mapping:1;		/* pagecache is invalid */
+	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 */
@@ -833,6 +837,9 @@ struct dfs_info3_param {
 #define CIFS_FATTR_DELETE_PENDING	0x2
 #define CIFS_FATTR_NEED_REVAL		0x4
 #define CIFS_FATTR_INO_COLLISION	0x8
+#define CIFS_FATTR_WINATTRS_VALID	0x10	/* T if cf_btime and cf_cifsattrs valid */
+#define CIFS_FATTR_UID_FAKED		0x20	/* T if cf_uid is faked */
+#define CIFS_FATTR_GID_FAKED		0x40	/* T if cf_gid is faked */
 
 struct cifs_fattr {
 	u32		cf_flags;
@@ -850,6 +857,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 d172c8e..d9e03ae 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -664,7 +664,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
 		return -ECHILD;
 
 	if (direntry->d_inode) {
-		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 745da3d..662d5ce 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -135,13 +135,21 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
 	set_nlink(inode, fattr->cf_nlink);
 	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;
@@ -248,15 +256,19 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info,
 		break;
 	}
 
-	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) {
 		fattr->cf_uid = cifs_sb->mnt_uid;
-	else
+		fattr->cf_flags |= CIFS_FATTR_UID_FAKED;
+	} else {
 		fattr->cf_uid = le64_to_cpu(info->Uid);
+	}
 
-	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) {
 		fattr->cf_gid = cifs_sb->mnt_gid;
-	else
+		fattr->cf_flags |= CIFS_FATTR_GID_FAKED;
+	} else {
 		fattr->cf_gid = le64_to_cpu(info->Gid);
+	}
 
 	fattr->cf_nlink = le64_to_cpu(info->Nlinks);
 }
@@ -283,7 +295,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;
 }
 
 int cifs_get_file_info_unix(struct file *filp)
@@ -510,6 +523,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;
@@ -521,6 +535,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;
@@ -1724,7 +1739,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)
 {
 	int xid;
 	int rc = 0;
@@ -1735,7 +1751,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 = GetXid();
@@ -1752,9 +1768,12 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
 		 "%ld jiffies %ld", 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);
 
@@ -1779,12 +1798,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 = dentry->d_inode;
 
-	rc = cifs_revalidate_dentry_attr(dentry);
+	rc = cifs_revalidate_dentry_attr(dentry, want_extra_bits, force);
 	if (rc)
 		return rc;
 
@@ -1796,11 +1816,30 @@ int cifs_revalidate_dentry(struct dentry *dentry)
 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 		 struct kstat *stat)
 {
+	struct cifsInodeInfo *cifs_i = CIFS_I(dentry->d_inode);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
 	struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
 	struct inode *inode = dentry->d_inode;
+	unsigned force = stat->query_flags & AT_FORCE_ATTR_SYNC;
+	bool want_extra_bits = false;
+	u32 info, ioc = 0;
+	u32 attrs;
 	int rc;
 
+	if (cifs_i->uid_faked)
+		stat->request_mask &= ~XSTAT_UID;
+	if (cifs_i->gid_faked)
+		stat->request_mask &= ~XSTAT_GID;
+
+	if (stat->request_mask & XSTAT_BTIME && !cifs_i->btime_valid) {
+		want_extra_bits = true;
+		force = true;
+	}
+	if (stat->request_mask & XSTAT_IOC_FLAGS) {
+		want_extra_bits = true;
+		force = true;
+	}
+
 	/*
 	 * We need to be sure that all dirty pages are written and the server
 	 * has actual ctime, mtime and file length.
@@ -1814,13 +1853,14 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 		}
 	}
 
-	rc = cifs_revalidate_dentry_attr(dentry);
-	if (rc)
-		return rc;
+	if (force || stat->request_mask & XSTAT_BASIC_STATS) {
+		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;
 
 	/*
 	 * If on a multiuser mount without unix extensions, and the admin hasn't
@@ -1834,7 +1874,53 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
 			stat->gid = current_fsgid();
 	}
-	return rc;
+
+	info = XSTAT_INFO_REMOTE | XSTAT_INFO_NONSYSTEM_OWNERSHIP;
+#ifdef CONFIG_CIFS_ACL
+	info |= XSTAT_INFO_HAS_ACL;
+#endif
+
+	if (cifs_i->btime_valid) {
+		stat->btime = cifs_i->btime;
+		stat->result_mask |= XSTAT_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 &= ~XSTAT_INO;
+
+	/*
+	 * If on a multiuser mount without unix extensions, and the admin
+	 * hasn't overridden them, set the ownership to the fsuid/fsgid of the
+	 * current process.
+	 */
+	if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) &&
+	    !tcon->unix_ext) {
+		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID))
+			stat->uid = current_fsuid();
+		if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
+			stat->gid = current_fsgid();
+	}
+	if (cifs_i->uid_faked)
+		stat->result_mask &= ~XSTAT_UID;
+	if (cifs_i->gid_faked)
+		stat->result_mask &= ~XSTAT_GID;
+
+	attrs = cifs_i->cifsAttrs;
+	if (attrs & ATTR_HIDDEN)	info |= XSTAT_INFO_HIDDEN;
+	if (attrs & ATTR_SYSTEM)	info |= XSTAT_INFO_SYSTEM;
+	if (attrs & ATTR_ARCHIVE)	info |= XSTAT_INFO_ARCHIVE;
+	if (attrs & ATTR_TEMPORARY)	info |= XSTAT_INFO_TEMPORARY;
+	if (attrs & ATTR_REPARSE)	info |= XSTAT_INFO_REPARSE_POINT;
+	if (attrs & ATTR_OFFLINE)	info |= XSTAT_INFO_OFFLINE;
+	if (attrs & ATTR_ENCRYPTED)	info |= XSTAT_INFO_ENCRYPTED;
+	stat->information |= info;
+
+	if (attrs & ATTR_READONLY)	ioc |= FS_IMMUTABLE_FL;
+	if (attrs & ATTR_COMPRESSED)	ioc |= FS_COMPR_FL;
+	stat->ioc_flags |= ioc;
+	return 0;
 }
 
 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
