aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-09-18 19:20:34 -0400
committerSteve French <smfrench@gmail.com>2012-09-24 22:46:30 -0400
commit6fc05c25ca35e65ee1759dd803f23576a268f5ec (patch)
tree048a8fa4bf1e8c0b486d8b037f0b7eaaf0b4c755
parent76ec5e33846de386f44826f145cd725b92c23630 (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.h2
-rw-r--r--fs/cifs/smb2ops.c22
-rw-r--r--fs/cifs/smb2pdu.c81
-rw-r--r--fs/cifs/smb2pdu.h19
-rw-r--r--fs/cifs/smb2proto.h3
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
28static int 30static int
29change_conf(struct TCP_Server_Info *server) 31change_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
527static int
528smb2_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
525struct smb_version_operations smb21_operations = { 546struct 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
583struct smb_version_values smb21_values = { 605struct 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
1975static void
1976copy_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
1987static int
1988build_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
2019int
2020SMB2_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
2051qinf_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
644struct 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,
138extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, 138extern 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);
141extern 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 */