Loading fs/cifs/smb2glob.h +2 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #ifndef _SMB2_GLOB_H #define _SMB2_GLOB_H #define SMB2_MAGIC_NUMBER 0xFE534D42 /* ***************************************************************** * Constants go here Loading fs/cifs/smb2ops.c +22 −0 Original line number Diff line number Diff line Loading @@ -18,12 +18,14 @@ */ #include <linux/pagemap.h> #include <linux/vfs.h> #include "cifsglob.h" #include "smb2pdu.h" #include "smb2proto.h" #include "cifsproto.h" #include "cifs_debug.h" #include "smb2status.h" #include "smb2glob.h" static int change_conf(struct TCP_Server_Info *server) Loading Loading @@ -522,6 +524,25 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, cinode->clientCanCacheRead ? 1 : 0); } static int smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, struct kstatfs *buf) { int rc; u64 persistent_fid, volatile_fid; __le16 srch_path = 0; /* Null - open root of share */ u8 oplock = SMB2_OPLOCK_LEVEL_NONE; rc = SMB2_open(xid, tcon, &srch_path, &persistent_fid, &volatile_fid, FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL); if (rc) return rc; buf->f_type = SMB2_MAGIC_NUMBER; rc = SMB2_QFS_info(xid, tcon, persistent_fid, volatile_fid, buf); SMB2_close(xid, tcon, persistent_fid, volatile_fid); return rc; } struct smb_version_operations smb21_operations = { .setup_request = smb2_setup_request, .setup_async_request = smb2_setup_async_request, Loading Loading @@ -578,6 +599,7 @@ struct smb_version_operations smb21_operations = { .calc_smb_size = smb2_calc_size, .is_status_pending = smb2_is_status_pending, .oplock_response = smb2_oplock_response, .queryfs = smb2_queryfs, }; struct smb_version_values smb21_values = { Loading fs/cifs/smb2pdu.c +81 −0 Original line number Diff line number Diff line Loading @@ -1971,3 +1971,84 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, return rc; } static void copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, struct kstatfs *kst) { kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) * le32_to_cpu(pfs_inf->SectorsPerAllocationUnit); kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits); kst->f_bfree = le64_to_cpu(pfs_inf->ActualAvailableAllocationUnits); kst->f_bavail = le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits); return; } static int build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level, int outbuf_len, u64 persistent_fid, u64 volatile_fid) { int rc; struct smb2_query_info_req *req; cFYI(1, "Query FSInfo level %d", level); if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) return -EIO; rc = small_smb2_init(SMB2_QUERY_INFO, tcon, (void **) &req); if (rc) return rc; req->InfoType = SMB2_O_INFO_FILESYSTEM; req->FileInfoClass = level; req->PersistentFileId = persistent_fid; req->VolatileFileId = volatile_fid; /* 4 for rfc1002 length field and 1 for pad */ req->InputBufferOffset = cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4); req->OutputBufferLength = cpu_to_le32( outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - 4); iov->iov_base = (char *)req; /* 4 for rfc1002 length field */ iov->iov_len = get_rfc1002_length(req) + 4; return 0; } int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata) { struct smb2_query_info_rsp *rsp = NULL; struct kvec iov; int rc = 0; int resp_buftype; struct cifs_ses *ses = tcon->ses; struct smb2_fs_full_size_info *info = NULL; rc = build_qfs_info_req(&iov, tcon, FS_FULL_SIZE_INFORMATION, sizeof(struct smb2_fs_full_size_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 qinf_exit; } rsp = (struct smb2_query_info_rsp *)iov.iov_base; info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ + le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr); rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset), le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr, sizeof(struct smb2_fs_full_size_info)); if (!rc) copy_fs_info_to_kstatfs(info, fsdata); qinf_exit: free_rsp_buf(resp_buftype, iov.iov_base); return rc; } fs/cifs/smb2pdu.h +19 −0 Original line number Diff line number Diff line Loading @@ -630,6 +630,25 @@ struct smb2_oplock_break { * BB consider moving to a different header */ /* File System Information Classes */ #define FS_VOLUME_INFORMATION 1 /* Query */ #define FS_LABEL_INFORMATION 2 /* Set */ #define FS_SIZE_INFORMATION 3 /* Query */ #define FS_DEVICE_INFORMATION 4 /* Query */ #define FS_ATTRIBUTE_INFORMATION 5 /* Query */ #define FS_CONTROL_INFORMATION 6 /* Query, Set */ #define FS_FULL_SIZE_INFORMATION 7 /* Query */ #define FS_OBJECT_ID_INFORMATION 8 /* Query, Set */ #define FS_DRIVER_PATH_INFORMATION 9 /* Query */ struct smb2_fs_full_size_info { __le64 TotalAllocationUnits; __le64 CallerAvailableAllocationUnits; __le64 ActualAvailableAllocationUnits; __le32 SectorsPerAllocationUnit; __le32 BytesPerSector; } __packed; /* partial list of QUERY INFO levels */ #define FILE_DIRECTORY_INFORMATION 1 #define FILE_FULL_DIRECTORY_INFORMATION 2 Loading fs/cifs/smb2proto.h +3 −0 Original line number Diff line number Diff line Loading @@ -138,5 +138,8 @@ extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, const u64 persistent_fid, const u64 volatile_fid, const __u8 oplock_level); extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id, struct kstatfs *FSData); #endif /* _SMB2PROTO_H */ Loading
fs/cifs/smb2glob.h +2 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ #ifndef _SMB2_GLOB_H #define _SMB2_GLOB_H #define SMB2_MAGIC_NUMBER 0xFE534D42 /* ***************************************************************** * Constants go here Loading
fs/cifs/smb2ops.c +22 −0 Original line number Diff line number Diff line Loading @@ -18,12 +18,14 @@ */ #include <linux/pagemap.h> #include <linux/vfs.h> #include "cifsglob.h" #include "smb2pdu.h" #include "smb2proto.h" #include "cifsproto.h" #include "cifs_debug.h" #include "smb2status.h" #include "smb2glob.h" static int change_conf(struct TCP_Server_Info *server) Loading Loading @@ -522,6 +524,25 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, cinode->clientCanCacheRead ? 1 : 0); } static int smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, struct kstatfs *buf) { int rc; u64 persistent_fid, volatile_fid; __le16 srch_path = 0; /* Null - open root of share */ u8 oplock = SMB2_OPLOCK_LEVEL_NONE; rc = SMB2_open(xid, tcon, &srch_path, &persistent_fid, &volatile_fid, FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL); if (rc) return rc; buf->f_type = SMB2_MAGIC_NUMBER; rc = SMB2_QFS_info(xid, tcon, persistent_fid, volatile_fid, buf); SMB2_close(xid, tcon, persistent_fid, volatile_fid); return rc; } struct smb_version_operations smb21_operations = { .setup_request = smb2_setup_request, .setup_async_request = smb2_setup_async_request, Loading Loading @@ -578,6 +599,7 @@ struct smb_version_operations smb21_operations = { .calc_smb_size = smb2_calc_size, .is_status_pending = smb2_is_status_pending, .oplock_response = smb2_oplock_response, .queryfs = smb2_queryfs, }; struct smb_version_values smb21_values = { Loading
fs/cifs/smb2pdu.c +81 −0 Original line number Diff line number Diff line Loading @@ -1971,3 +1971,84 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, return rc; } static void copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, struct kstatfs *kst) { kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) * le32_to_cpu(pfs_inf->SectorsPerAllocationUnit); kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits); kst->f_bfree = le64_to_cpu(pfs_inf->ActualAvailableAllocationUnits); kst->f_bavail = le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits); return; } static int build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level, int outbuf_len, u64 persistent_fid, u64 volatile_fid) { int rc; struct smb2_query_info_req *req; cFYI(1, "Query FSInfo level %d", level); if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) return -EIO; rc = small_smb2_init(SMB2_QUERY_INFO, tcon, (void **) &req); if (rc) return rc; req->InfoType = SMB2_O_INFO_FILESYSTEM; req->FileInfoClass = level; req->PersistentFileId = persistent_fid; req->VolatileFileId = volatile_fid; /* 4 for rfc1002 length field and 1 for pad */ req->InputBufferOffset = cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4); req->OutputBufferLength = cpu_to_le32( outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - 4); iov->iov_base = (char *)req; /* 4 for rfc1002 length field */ iov->iov_len = get_rfc1002_length(req) + 4; return 0; } int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata) { struct smb2_query_info_rsp *rsp = NULL; struct kvec iov; int rc = 0; int resp_buftype; struct cifs_ses *ses = tcon->ses; struct smb2_fs_full_size_info *info = NULL; rc = build_qfs_info_req(&iov, tcon, FS_FULL_SIZE_INFORMATION, sizeof(struct smb2_fs_full_size_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 qinf_exit; } rsp = (struct smb2_query_info_rsp *)iov.iov_base; info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ + le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr); rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset), le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr, sizeof(struct smb2_fs_full_size_info)); if (!rc) copy_fs_info_to_kstatfs(info, fsdata); qinf_exit: free_rsp_buf(resp_buftype, iov.iov_base); return rc; }
fs/cifs/smb2pdu.h +19 −0 Original line number Diff line number Diff line Loading @@ -630,6 +630,25 @@ struct smb2_oplock_break { * BB consider moving to a different header */ /* File System Information Classes */ #define FS_VOLUME_INFORMATION 1 /* Query */ #define FS_LABEL_INFORMATION 2 /* Set */ #define FS_SIZE_INFORMATION 3 /* Query */ #define FS_DEVICE_INFORMATION 4 /* Query */ #define FS_ATTRIBUTE_INFORMATION 5 /* Query */ #define FS_CONTROL_INFORMATION 6 /* Query, Set */ #define FS_FULL_SIZE_INFORMATION 7 /* Query */ #define FS_OBJECT_ID_INFORMATION 8 /* Query, Set */ #define FS_DRIVER_PATH_INFORMATION 9 /* Query */ struct smb2_fs_full_size_info { __le64 TotalAllocationUnits; __le64 CallerAvailableAllocationUnits; __le64 ActualAvailableAllocationUnits; __le32 SectorsPerAllocationUnit; __le32 BytesPerSector; } __packed; /* partial list of QUERY INFO levels */ #define FILE_DIRECTORY_INFORMATION 1 #define FILE_FULL_DIRECTORY_INFORMATION 2 Loading
fs/cifs/smb2proto.h +3 −0 Original line number Diff line number Diff line Loading @@ -138,5 +138,8 @@ extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, const u64 persistent_fid, const u64 volatile_fid, const __u8 oplock_level); extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_file_id, u64 volatile_file_id, struct kstatfs *FSData); #endif /* _SMB2PROTO_H */