aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2pdu.c
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 /fs/cifs/smb2pdu.c
parent76ec5e33846de386f44826f145cd725b92c23630 (diff)
CIFS: Add statfs support for SMB2
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r--fs/cifs/smb2pdu.c81
1 files changed, 81 insertions, 0 deletions
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}