/* close a file */
        void (*close)(const unsigned int, struct cifs_tcon *,
                      struct cifs_fid *);
+       /* close a file, returning file attributes and timestamps */
+       void (*close_getattr)(const unsigned int xid, struct cifs_tcon *tcon,
+                     struct cifsFileInfo *pfile_info);
        /* send a flush request to the server */
        int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
        /* async read from the server */
 
                unsigned int xid;
 
                xid = get_xid();
-               if (server->ops->close)
+               if (server->ops->close_getattr)
+                       server->ops->close_getattr(xid, tcon, cifs_file);
+               else if (server->ops->close)
                        server->ops->close(xid, tcon, &cifs_file->fid);
                _free_xid(xid);
        }
 
        rqst[num_rqst].rq_iov = close_iov;
        rqst[num_rqst].rq_nvec = 1;
        rc = SMB2_close_init(tcon, &rqst[num_rqst], COMPOUND_FID,
-                            COMPOUND_FID);
+                            COMPOUND_FID, false);
        smb2_set_related(&rqst[num_rqst]);
        if (rc)
                goto finished;
 
        memset(&close_iov, 0, sizeof(close_iov));
        rqst[2].rq_iov = close_iov;
        rqst[2].rq_nvec = 1;
-       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
+       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
        smb2_set_related(&rqst[2]);
 
        rc = compound_send_recv(xid, ses, flags, 3, rqst,
        SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
 }
 
+static void
+smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
+                  struct cifsFileInfo *cfile)
+{
+       struct smb2_file_network_open_info file_inf;
+       struct inode *inode;
+       int rc;
+
+       rc = __SMB2_close(xid, tcon, cfile->fid.persistent_fid,
+                  cfile->fid.volatile_fid, &file_inf);
+       if (rc)
+               return;
+
+       inode = d_inode(cfile->dentry);
+
+       spin_lock(&inode->i_lock);
+       CIFS_I(inode)->time = jiffies;
+
+       /* Creation time should not need to be updated on close */
+       if (file_inf.LastWriteTime)
+               inode->i_mtime = cifs_NTtimeToUnix(file_inf.LastWriteTime);
+       if (file_inf.ChangeTime)
+               inode->i_ctime = cifs_NTtimeToUnix(file_inf.ChangeTime);
+       if (file_inf.LastAccessTime)
+               inode->i_atime = cifs_NTtimeToUnix(file_inf.LastAccessTime);
+
+       /*
+        * i_blocks is not related to (i_size / i_blksize),
+        * but instead 512 byte (2**9) size is required for
+        * calculating num blocks.
+        */
+       if (le64_to_cpu(file_inf.AllocationSize) > 4096)
+               inode->i_blocks =
+                       (512 - 1 + le64_to_cpu(file_inf.AllocationSize)) >> 9;
+
+       /* End of file and Attributes should not have to be updated on close */
+       spin_unlock(&inode->i_lock);
+}
+
 static int
 SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
                     u64 persistent_fid, u64 volatile_fid,
        rqst[2].rq_iov = close_iov;
        rqst[2].rq_nvec = 1;
 
-       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
+       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
        if (rc)
                goto iqinf_exit;
        smb2_set_related(&rqst[2]);
        rqst[2].rq_iov = close_iov;
        rqst[2].rq_nvec = 1;
 
-       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
+       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
        if (rc)
                goto qic_exit;
        smb2_set_related(&rqst[2]);
        rqst[2].rq_iov = close_iov;
        rqst[2].rq_nvec = 1;
 
-       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
+       rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
        if (rc)
                goto querty_exit;
 
        .open = smb2_open_file,
        .set_fid = smb2_set_fid,
        .close = smb2_close_file,
+       .close_getattr = smb2_close_getattr,
        .flush = smb2_flush_file,
        .async_readv = smb2_async_readv,
        .async_writev = smb2_async_writev,
        .open = smb2_open_file,
        .set_fid = smb2_set_fid,
        .close = smb2_close_file,
+       .close_getattr = smb2_close_getattr,
        .flush = smb2_flush_file,
        .async_readv = smb2_async_readv,
        .async_writev = smb2_async_writev,
 
 
 int
 SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
-               u64 persistent_fid, u64 volatile_fid)
+               u64 persistent_fid, u64 volatile_fid, bool query_attrs)
 {
        struct smb2_close_req *req;
        struct kvec *iov = rqst->rq_iov;
 
        req->PersistentFileId = persistent_fid;
        req->VolatileFileId = volatile_fid;
+       if (query_attrs)
+               req->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
+       else
+               req->Flags = 0;
        iov[0].iov_base = (char *)req;
        iov[0].iov_len = total_len;
 
 }
 
 int
-SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
-                u64 persistent_fid, u64 volatile_fid)
+__SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
+            u64 persistent_fid, u64 volatile_fid,
+            struct smb2_file_network_open_info *pbuf)
 {
        struct smb_rqst rqst;
        struct smb2_close_rsp *rsp = NULL;
        int resp_buftype = CIFS_NO_BUFFER;
        int rc = 0;
        int flags = 0;
+       bool query_attrs = false;
 
        cifs_dbg(FYI, "Close\n");
 
        rqst.rq_iov = iov;
        rqst.rq_nvec = 1;
 
+       /* check if need to ask server to return timestamps in close response */
+       if (pbuf)
+               query_attrs = true;
+
        trace_smb3_close_enter(xid, persistent_fid, tcon->tid, ses->Suid);
-       rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid);
+       rc = SMB2_close_init(tcon, &rqst, persistent_fid, volatile_fid,
+                            query_attrs);
        if (rc)
                goto close_exit;
 
                trace_smb3_close_err(xid, persistent_fid, tcon->tid, ses->Suid,
                                     rc);
                goto close_exit;
-       } else
+       } else {
                trace_smb3_close_done(xid, persistent_fid, tcon->tid,
                                      ses->Suid);
+               /*
+                * Note that have to subtract 4 since struct network_open_info
+                * has a final 4 byte pad that close response does not have
+                */
+               if (pbuf)
+                       memcpy(pbuf, (char *)&rsp->CreationTime, sizeof(*pbuf) - 4);
+       }
 
        atomic_dec(&tcon->num_remote_opens);
-
-       /* BB FIXME - decode close response, update inode for caching */
-
 close_exit:
        SMB2_close_free(&rqst);
        free_rsp_buf(resp_buftype, rsp);
        return rc;
 }
 
+int
+SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
+               u64 persistent_fid, u64 volatile_fid)
+{
+       return __SMB2_close(xid, tcon, persistent_fid, volatile_fid, NULL);
+}
+
 int
 smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
                  struct kvec *iov, unsigned int min_buf_size)
 
        __le64 EndOfFile; /* new end of file value */
 } __packed; /* level 20 Set */
 
+struct smb2_file_network_open_info {
+       __le64 CreationTime;
+       __le64 LastAccessTime;
+       __le64 LastWriteTime;
+       __le64 ChangeTime;
+       __le64 AllocationSize;
+       __le64 EndOfFile;
+       __le32 Attributes;
+       __le32 Reserved;
+} __packed; /* level 34 Query also similar returned in close rsp and open rsp */
+
 extern char smb2_padding[7];
 
 #endif                         /* _SMB2PDU_H */
 
                        u64 persistent_fid, u64 volatile_fid, bool watch_tree,
                        u32 completion_filter);
 
+extern int __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
+                       u64 persistent_fid, u64 volatile_fid,
+                       struct smb2_file_network_open_info *pbuf);
 extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
                      u64 persistent_file_id, u64 volatile_file_id);
 extern int SMB2_close_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
-                     u64 persistent_file_id, u64 volatile_file_id);
+                     u64 persistent_fid, u64 volatile_fid, bool query_attrs);
 extern void SMB2_close_free(struct smb_rqst *rqst);
 extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
                      u64 persistent_file_id, u64 volatile_file_id);