diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index a53e2053ae9df9699ebfc1e85cf9ed5c69f4197c..79084d67f3fb2293b3ebc87608818bf9f6d5dc0c 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -229,7 +229,10 @@ smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon) if (rc) return; - SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid); + SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid, + FS_ATTRIBUTE_INFORMATION); + SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid, + FS_DEVICE_INFORMATION); SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); return; } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index df12cf8bd979719d8d53bd17d937a0b9dcdd31e4..7887cf50e5fb101cb0bba642eb1f91734ee28aa0 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2358,17 +2358,27 @@ SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, int SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, - u64 persistent_fid, u64 volatile_fid) + u64 persistent_fid, u64 volatile_fid, int level) { struct smb2_query_info_rsp *rsp = NULL; struct kvec iov; int rc = 0; - int resp_buftype; + int resp_buftype, max_len, min_len; 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), + if (level == FS_DEVICE_INFORMATION) { + max_len = sizeof(FILE_SYSTEM_DEVICE_INFO); + min_len = sizeof(FILE_SYSTEM_DEVICE_INFO); + } else if (level == FS_ATTRIBUTE_INFORMATION) { + max_len = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO); + min_len = MIN_FS_ATTR_INFO_SIZE; + } else { + cifs_dbg(FYI, "Invalid qfsinfo level %d", level); + return -EINVAL; + } + + rc = build_qfs_info_req(&iov, tcon, level, max_len, persistent_fid, volatile_fid); if (rc) return rc; @@ -2382,12 +2392,17 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, 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) { + rc = validate_buf(offset, rsp_len, &rsp->hdr, min_len); + if (rc) + goto qfsattr_exit; + + if (level == FS_ATTRIBUTE_INFORMATION) memcpy(&tcon->fsAttrInfo, 4 /* RFC1001 len */ + offset + (char *)&rsp->hdr, min_t(unsigned int, - rsp_len, sizeof(FILE_SYSTEM_ATTRIBUTE_INFO))); - } + rsp_len, max_len)); + else if (level == FS_DEVICE_INFORMATION) + memcpy(&tcon->fsDevInfo, 4 /* RFC1001 len */ + offset + + (char *)&rsp->hdr, sizeof(FILE_SYSTEM_DEVICE_INFO)); qfsattr_exit: free_rsp_buf(resp_buftype, iov.iov_base); diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 68dc00d5fb126fb3c8ea218724a1a8c56d4aa06e..313813e4c19b300357bfc5f6db225a3be85d1121 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -151,7 +151,7 @@ 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); + u64 persistent_file_id, u64 volatile_file_id, int lvl); extern int SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon, const __u64 persist_fid, const __u64 volatile_fid, const __u32 pid, const __u64 length, const __u64 offset,