diff mbox

[CIFS] Query file system attributes from server on SMB2, not just cifs, mounts

Message ID CAH2r5muWeLvm8tqKCmUftnXL3F-5KX0J0+QRH_cuS57LGTKKXQ@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Steve French Oct. 9, 2013, 7:11 a.m. UTC
Currently SMB2 and SMB3 mounts do not query the file system attributes
from the server at mount time as is done for cifs.  These can be
useful for debugging.  These could be used in the future to determine
when
we are able to request certain optional features (compressed files e.g.)
of the protocol.

Signed-off-by: Steve French <smfrench@gmail.com>
---
 fs/cifs/cifspdu.h   |  3 +++
 fs/cifs/smb2ops.c   | 28 ++++++++++++++++++++++++++++
 fs/cifs/smb2pdu.c   | 42 ++++++++++++++++++++++++++++++++++++++++--
 fs/cifs/smb2proto.h |  2 ++
 4 files changed, 73 insertions(+), 2 deletions(-)

      const __u32 pid, const __u64 length, const __u64 offset,
diff mbox

Patch

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,