diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 08f9dfb..d40bd77 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -2215,6 +2215,9 @@ typedef struct {
  __le32 DeviceCharacteristics;
 } __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info
level 0x104 */

+/* minimum includes first three fields, and empty FS Name */
+#define MIN_FS_ATTR_INFO_SIZE 12
+
 typedef struct {
  __le32 Attributes;
  __le32 MaxPathNameComponentLength;
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index b96bacc..a53e205 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -209,6 +209,31 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon,
struct smb_vol *volume_info)
  return rsize;
 }

+static void
+smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
+{
+ int rc;
+ __le16 srch_path = 0; /* Null - open root of share */
+ u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+ struct cifs_open_parms oparms;
+ struct cifs_fid fid;
+
+ oparms.tcon = tcon;
+ oparms.desired_access = FILE_READ_ATTRIBUTES;
+ oparms.disposition = FILE_OPEN;
+ oparms.create_options = 0;
+ oparms.fid = &fid;
+ oparms.reconnect = false;
+
+ rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL);
+ if (rc)
+ return;
+
+ SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+ SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+ return;
+}
+
 static int
 smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
  struct cifs_sb_info *cifs_sb, const char *full_path)
@@ -873,6 +898,7 @@ struct smb_version_operations smb20_operations = {
  .logoff = SMB2_logoff,
  .tree_connect = SMB2_tcon,
  .tree_disconnect = SMB2_tdis,
+ .qfs_tcon = smb2_qfs_tcon,
  .is_path_accessible = smb2_is_path_accessible,
  .can_echo = smb2_can_echo,
  .echo = SMB2_echo,
@@ -945,6 +971,7 @@ struct smb_version_operations smb21_operations = {
  .logoff = SMB2_logoff,
  .tree_connect = SMB2_tcon,
  .tree_disconnect = SMB2_tdis,
+ .qfs_tcon = smb2_qfs_tcon,
  .is_path_accessible = smb2_is_path_accessible,
  .can_echo = smb2_can_echo,
  .echo = SMB2_echo,
@@ -1018,6 +1045,7 @@ struct smb_version_operations smb30_operations = {
  .logoff = SMB2_logoff,
  .tree_connect = SMB2_tcon,
  .tree_disconnect = SMB2_tdis,
+ .qfs_tcon = smb2_qfs_tcon,
  .is_path_accessible = smb2_is_path_accessible,
  .can_echo = smb2_can_echo,
  .echo = SMB2_echo,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index fb19ad8..2ade58b 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2328,7 +2328,7 @@ SMB2_QFS_info(const unsigned int xid, struct
cifs_tcon *tcon,
  rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0);
  if (rc) {
  cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
- goto qinf_exit;
+ goto qfsinf_exit;
  }
  rsp = (struct smb2_query_info_rsp *)iov.iov_base;

@@ -2340,7 +2340,45 @@ SMB2_QFS_info(const unsigned int xid, struct
cifs_tcon *tcon,
  if (!rc)
  copy_fs_info_to_kstatfs(info, fsdata);

-qinf_exit:
+qfsinf_exit:
+ free_rsp_buf(resp_buftype, iov.iov_base);
+ return rc;
+}
+
+int
+SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
+      u64 persistent_fid, u64 volatile_fid)
+{
+ struct smb2_query_info_rsp *rsp = NULL;
+ struct kvec iov;
+ int rc = 0;
+ int resp_buftype;
+ struct cifs_ses *ses = tcon->ses;
+ unsigned int rsp_len, offset;
+
+ rc = build_qfs_info_req(&iov, tcon, SMB_QUERY_FS_ATTRIBUTE_INFO,
+ sizeof(FILE_SYSTEM_ATTRIBUTE_INFO),
+ persistent_fid, volatile_fid);
+ if (rc)
+ return rc;
+
+ rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0);
+ if (rc) {
+ cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
+ goto qfsattr_exit;
+ }
+ rsp = (struct smb2_query_info_rsp *)iov.iov_base;
+
+ rsp_len = le32_to_cpu(rsp->OutputBufferLength);
+ offset = le16_to_cpu(rsp->OutputBufferOffset);
+ rc = validate_buf(offset, rsp_len, &rsp->hdr, MIN_FS_ATTR_INFO_SIZE);
+ if (!rc) {
+ memcpy(&tcon->fsAttrInfo, 4 /* RFC1001 len */ + offset
+ + (char *)&rsp->hdr, min_t(unsigned int,
+ rsp_len, sizeof(FILE_SYSTEM_ATTRIBUTE_INFO)));
+ }
+
+qfsattr_exit:
  free_rsp_buf(resp_buftype, iov.iov_base);
  return rc;
 }
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 3cf22e3..68dc00d 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -150,6 +150,8 @@ extern int SMB2_oplock_break(const unsigned int
xid, struct cifs_tcon *tcon,
 extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
  u64 persistent_file_id, u64 volatile_file_id,
  struct kstatfs *FSData);
+extern int SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_file_id, u64 volatile_file_id);
 extern int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon,
      const __u64 persist_fid, const __u64 volatile_fid,
