diff options
author | Pavel Shilovsky <pshilovsky@samba.org> | 2012-09-18 19:20:34 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2012-09-24 22:46:30 -0400 |
commit | 6fc05c25ca35e65ee1759dd803f23576a268f5ec (patch) | |
tree | 048a8fa4bf1e8c0b486d8b037f0b7eaaf0b4c755 | |
parent | 76ec5e33846de386f44826f145cd725b92c23630 (diff) |
CIFS: Add statfs support for SMB2
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <smfrench@gmail.com>
-rw-r--r-- | fs/cifs/smb2glob.h | 2 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 22 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 81 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 19 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 3 |
5 files changed, 127 insertions, 0 deletions
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h index 05d429b1c37e..7c0e2143e775 100644 --- a/fs/cifs/smb2glob.h +++ b/fs/cifs/smb2glob.h | |||
@@ -23,6 +23,8 @@ | |||
23 | #ifndef _SMB2_GLOB_H | 23 | #ifndef _SMB2_GLOB_H |
24 | #define _SMB2_GLOB_H | 24 | #define _SMB2_GLOB_H |
25 | 25 | ||
26 | #define SMB2_MAGIC_NUMBER 0xFE534D42 | ||
27 | |||
26 | /* | 28 | /* |
27 | ***************************************************************** | 29 | ***************************************************************** |
28 | * Constants go here | 30 | * Constants go here |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 8c72e0768d12..3a8c68258026 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -18,12 +18,14 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/pagemap.h> | 20 | #include <linux/pagemap.h> |
21 | #include <linux/vfs.h> | ||
21 | #include "cifsglob.h" | 22 | #include "cifsglob.h" |
22 | #include "smb2pdu.h" | 23 | #include "smb2pdu.h" |
23 | #include "smb2proto.h" | 24 | #include "smb2proto.h" |
24 | #include "cifsproto.h" | 25 | #include "cifsproto.h" |
25 | #include "cifs_debug.h" | 26 | #include "cifs_debug.h" |
26 | #include "smb2status.h" | 27 | #include "smb2status.h" |
28 | #include "smb2glob.h" | ||
27 | 29 | ||
28 | static int | 30 | static int |
29 | change_conf(struct TCP_Server_Info *server) | 31 | change_conf(struct TCP_Server_Info *server) |
@@ -522,6 +524,25 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid, | |||
522 | cinode->clientCanCacheRead ? 1 : 0); | 524 | cinode->clientCanCacheRead ? 1 : 0); |
523 | } | 525 | } |
524 | 526 | ||
527 | static int | ||
528 | smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon, | ||
529 | struct kstatfs *buf) | ||
530 | { | ||
531 | int rc; | ||
532 | u64 persistent_fid, volatile_fid; | ||
533 | __le16 srch_path = 0; /* Null - open root of share */ | ||
534 | u8 oplock = SMB2_OPLOCK_LEVEL_NONE; | ||
535 | |||
536 | rc = SMB2_open(xid, tcon, &srch_path, &persistent_fid, &volatile_fid, | ||
537 | FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL); | ||
538 | if (rc) | ||
539 | return rc; | ||
540 | buf->f_type = SMB2_MAGIC_NUMBER; | ||
541 | rc = SMB2_QFS_info(xid, tcon, persistent_fid, volatile_fid, buf); | ||
542 | SMB2_close(xid, tcon, persistent_fid, volatile_fid); | ||
543 | return rc; | ||
544 | } | ||
545 | |||
525 | struct smb_version_operations smb21_operations = { | 546 | struct smb_version_operations smb21_operations = { |
526 | .setup_request = smb2_setup_request, | 547 | .setup_request = smb2_setup_request, |
527 | .setup_async_request = smb2_setup_async_request, | 548 | .setup_async_request = smb2_setup_async_request, |
@@ -578,6 +599,7 @@ struct smb_version_operations smb21_operations = { | |||
578 | .calc_smb_size = smb2_calc_size, | 599 | .calc_smb_size = smb2_calc_size, |
579 | .is_status_pending = smb2_is_status_pending, | 600 | .is_status_pending = smb2_is_status_pending, |
580 | .oplock_response = smb2_oplock_response, | 601 | .oplock_response = smb2_oplock_response, |
602 | .queryfs = smb2_queryfs, | ||
581 | }; | 603 | }; |
582 | 604 | ||
583 | struct smb_version_values smb21_values = { | 605 | struct smb_version_values smb21_values = { |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 566d86b0ad96..994c184ac9a9 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -1971,3 +1971,84 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, | |||
1971 | 1971 | ||
1972 | return rc; | 1972 | return rc; |
1973 | } | 1973 | } |
1974 | |||
1975 | static void | ||
1976 | copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, | ||
1977 | struct kstatfs *kst) | ||
1978 | { | ||
1979 | kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) * | ||
1980 | le32_to_cpu(pfs_inf->SectorsPerAllocationUnit); | ||
1981 | kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits); | ||
1982 | kst->f_bfree = le64_to_cpu(pfs_inf->ActualAvailableAllocationUnits); | ||
1983 | kst->f_bavail = le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits); | ||
1984 | return; | ||
1985 | } | ||
1986 | |||
1987 | static int | ||
1988 | build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level, | ||
1989 | int outbuf_len, u64 persistent_fid, u64 volatile_fid) | ||
1990 | { | ||
1991 | int rc; | ||
1992 | struct smb2_query_info_req *req; | ||
1993 | |||
1994 | cFYI(1, "Query FSInfo level %d", level); | ||
1995 | |||
1996 | if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) | ||
1997 | return -EIO; | ||
1998 | |||
1999 | rc = small_smb2_init(SMB2_QUERY_INFO, tcon, (void **) &req); | ||
2000 | if (rc) | ||
2001 | return rc; | ||
2002 | |||
2003 | req->InfoType = SMB2_O_INFO_FILESYSTEM; | ||
2004 | req->FileInfoClass = level; | ||
2005 | req->PersistentFileId = persistent_fid; | ||
2006 | req->VolatileFileId = volatile_fid; | ||
2007 | /* 4 for rfc1002 length field and 1 for pad */ | ||
2008 | req->InputBufferOffset = | ||
2009 | cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4); | ||
2010 | req->OutputBufferLength = cpu_to_le32( | ||
2011 | outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - 4); | ||
2012 | |||
2013 | iov->iov_base = (char *)req; | ||
2014 | /* 4 for rfc1002 length field */ | ||
2015 | iov->iov_len = get_rfc1002_length(req) + 4; | ||
2016 | return 0; | ||
2017 | } | ||
2018 | |||
2019 | int | ||
2020 | SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, | ||
2021 | u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata) | ||
2022 | { | ||
2023 | struct smb2_query_info_rsp *rsp = NULL; | ||
2024 | struct kvec iov; | ||
2025 | int rc = 0; | ||
2026 | int resp_buftype; | ||
2027 | struct cifs_ses *ses = tcon->ses; | ||
2028 | struct smb2_fs_full_size_info *info = NULL; | ||
2029 | |||
2030 | rc = build_qfs_info_req(&iov, tcon, FS_FULL_SIZE_INFORMATION, | ||
2031 | sizeof(struct smb2_fs_full_size_info), | ||
2032 | persistent_fid, volatile_fid); | ||
2033 | if (rc) | ||
2034 | return rc; | ||
2035 | |||
2036 | rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0); | ||
2037 | if (rc) { | ||
2038 | cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE); | ||
2039 | goto qinf_exit; | ||
2040 | } | ||
2041 | rsp = (struct smb2_query_info_rsp *)iov.iov_base; | ||
2042 | |||
2043 | info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ + | ||
2044 | le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr); | ||
2045 | rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset), | ||
2046 | le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr, | ||
2047 | sizeof(struct smb2_fs_full_size_info)); | ||
2048 | if (!rc) | ||
2049 | copy_fs_info_to_kstatfs(info, fsdata); | ||
2050 | |||
2051 | qinf_exit: | ||
2052 | free_rsp_buf(resp_buftype, iov.iov_base); | ||
2053 | return rc; | ||
2054 | } | ||
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 8a0745764297..3c8e99ea88ad 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h | |||
@@ -630,6 +630,25 @@ struct smb2_oplock_break { | |||
630 | * BB consider moving to a different header | 630 | * BB consider moving to a different header |
631 | */ | 631 | */ |
632 | 632 | ||
633 | /* File System Information Classes */ | ||
634 | #define FS_VOLUME_INFORMATION 1 /* Query */ | ||
635 | #define FS_LABEL_INFORMATION 2 /* Set */ | ||
636 | #define FS_SIZE_INFORMATION 3 /* Query */ | ||
637 | #define FS_DEVICE_INFORMATION 4 /* Query */ | ||
638 | #define FS_ATTRIBUTE_INFORMATION 5 /* Query */ | ||
639 | #define FS_CONTROL_INFORMATION 6 /* Query, Set */ | ||
640 | #define FS_FULL_SIZE_INFORMATION 7 /* Query */ | ||
641 | #define FS_OBJECT_ID_INFORMATION 8 /* Query, Set */ | ||
642 | #define FS_DRIVER_PATH_INFORMATION 9 /* Query */ | ||
643 | |||
644 | struct smb2_fs_full_size_info { | ||
645 | __le64 TotalAllocationUnits; | ||
646 | __le64 CallerAvailableAllocationUnits; | ||
647 | __le64 ActualAvailableAllocationUnits; | ||
648 | __le32 SectorsPerAllocationUnit; | ||
649 | __le32 BytesPerSector; | ||
650 | } __packed; | ||
651 | |||
633 | /* partial list of QUERY INFO levels */ | 652 | /* partial list of QUERY INFO levels */ |
634 | #define FILE_DIRECTORY_INFORMATION 1 | 653 | #define FILE_DIRECTORY_INFORMATION 1 |
635 | #define FILE_FULL_DIRECTORY_INFORMATION 2 | 654 | #define FILE_FULL_DIRECTORY_INFORMATION 2 |
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index de554b716fdf..a73a963af8f4 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
@@ -138,5 +138,8 @@ extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon, | |||
138 | extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, | 138 | extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, |
139 | const u64 persistent_fid, const u64 volatile_fid, | 139 | const u64 persistent_fid, const u64 volatile_fid, |
140 | const __u8 oplock_level); | 140 | const __u8 oplock_level); |
141 | extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, | ||
142 | u64 persistent_file_id, u64 volatile_file_id, | ||
143 | struct kstatfs *FSData); | ||
141 | 144 | ||
142 | #endif /* _SMB2PROTO_H */ | 145 | #endif /* _SMB2PROTO_H */ |