aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorPavel Shilovsky <pshilovsky@samba.org>2012-09-18 19:20:26 -0400
committerSteve French <smfrench@gmail.com>2012-09-24 22:46:26 -0400
commitf0df737ee820ec62055baf2b28e24db4fb1ad71d (patch)
treebb2aa80babbe6afaa1edcfb1885ad3b8250171c0 /fs
parent0ff78a221bf7839a7f20be9929433d17e868e987 (diff)
CIFS: Add open/close file support for SMB2
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/Makefile2
-rw-r--r--fs/cifs/cifsglob.h4
-rw-r--r--fs/cifs/smb2file.c86
-rw-r--r--fs/cifs/smb2inode.c4
-rw-r--r--fs/cifs/smb2ops.c22
-rw-r--r--fs/cifs/smb2pdu.c53
-rw-r--r--fs/cifs/smb2pdu.h4
-rw-r--r--fs/cifs/smb2proto.h14
8 files changed, 172 insertions, 17 deletions
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index feee94309271..aa0d68b086eb 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -17,4 +17,4 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
17cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o 17cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
18 18
19cifs-$(CONFIG_CIFS_SMB2) += smb2ops.o smb2maperror.o smb2transport.o \ 19cifs-$(CONFIG_CIFS_SMB2) += smb2ops.o smb2maperror.o smb2transport.o \
20 smb2misc.o smb2pdu.o smb2inode.o 20 smb2misc.o smb2pdu.o smb2inode.o smb2file.o
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 39bf2f3e866a..8a69dae81d3a 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -757,6 +757,10 @@ struct cifs_search_info {
757 757
758struct cifs_fid { 758struct cifs_fid {
759 __u16 netfid; 759 __u16 netfid;
760#ifdef CONFIG_CIFS_SMB2
761 __u64 persistent_fid; /* persist file id for smb2 */
762 __u64 volatile_fid; /* volatile file id for smb2 */
763#endif
760}; 764};
761 765
762struct cifsFileInfo { 766struct cifsFileInfo {
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
new file mode 100644
index 000000000000..a7618dfb7712
--- /dev/null
+++ b/fs/cifs/smb2file.c
@@ -0,0 +1,86 @@
1/*
2 * fs/cifs/smb2file.c
3 *
4 * Copyright (C) International Business Machines Corp., 2002, 2011
5 * Author(s): Steve French (sfrench@us.ibm.com),
6 * Pavel Shilovsky ((pshilovsky@samba.org) 2012
7 *
8 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published
10 * by the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
16 * the GNU Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22#include <linux/fs.h>
23#include <linux/stat.h>
24#include <linux/slab.h>
25#include <linux/pagemap.h>
26#include <asm/div64.h>
27#include "cifsfs.h"
28#include "cifspdu.h"
29#include "cifsglob.h"
30#include "cifsproto.h"
31#include "cifs_debug.h"
32#include "cifs_fs_sb.h"
33#include "cifs_unicode.h"
34#include "fscache.h"
35#include "smb2proto.h"
36
37int
38smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
39 int disposition, int desired_access, int create_options,
40 struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
41 struct cifs_sb_info *cifs_sb)
42{
43 int rc;
44 __le16 *smb2_path;
45 struct smb2_file_all_info *smb2_data = NULL;
46
47 smb2_path = cifs_convert_path_to_utf16(path, cifs_sb);
48 if (smb2_path == NULL) {
49 rc = -ENOMEM;
50 goto out;
51 }
52
53 smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
54 GFP_KERNEL);
55 if (smb2_data == NULL) {
56 rc = -ENOMEM;
57 goto out;
58 }
59
60 desired_access |= FILE_READ_ATTRIBUTES;
61
62 rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
63 &fid->volatile_fid, desired_access, disposition,
64 0, 0, smb2_data);
65 if (rc)
66 goto out;
67
68 if (buf) {
69 /* open response does not have IndexNumber field - get it */
70 rc = SMB2_get_srv_num(xid, tcon, fid->persistent_fid,
71 fid->volatile_fid,
72 &smb2_data->IndexNumber);
73 if (rc) {
74 /* let get_inode_info disable server inode numbers */
75 smb2_data->IndexNumber = 0;
76 rc = 0;
77 }
78 move_smb2_info_to_cifs(buf, smb2_data);
79 }
80
81out:
82 *oplock = 0;
83 kfree(smb2_data);
84 kfree(smb2_path);
85 return rc;
86}
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 02a9bda4248c..ee3a1ef686dd 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -54,7 +54,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
54 54
55 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid, 55 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
56 desired_access, create_disposition, file_attributes, 56 desired_access, create_disposition, file_attributes,
57 create_options); 57 create_options, NULL);
58 if (rc) { 58 if (rc) {
59 kfree(utf16_path); 59 kfree(utf16_path);
60 return rc; 60 return rc;
@@ -86,7 +86,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
86 return rc; 86 return rc;
87} 87}
88 88
89static void 89void
90move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src) 90move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
91{ 91{
92 memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src); 92 memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src);
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index bf9b318cfa4b..eba12b31dc60 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -170,7 +170,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
170 return -ENOMEM; 170 return -ENOMEM;
171 171
172 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid, 172 rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
173 FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0); 173 FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, NULL);
174 if (rc) { 174 if (rc) {
175 kfree(utf16_path); 175 kfree(utf16_path);
176 return rc; 176 return rc;
@@ -292,6 +292,23 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
292#endif 292#endif
293} 293}
294 294
295static void
296smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
297{
298 /* struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); */
299 cfile->fid.persistent_fid = fid->persistent_fid;
300 cfile->fid.volatile_fid = fid->volatile_fid;
301 /* cifs_set_oplock_level(cinode, oplock); */
302 /* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */
303}
304
305static int
306smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
307 struct cifs_fid *fid)
308{
309 return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
310}
311
295struct smb_version_operations smb21_operations = { 312struct smb_version_operations smb21_operations = {
296 .setup_request = smb2_setup_request, 313 .setup_request = smb2_setup_request,
297 .setup_async_request = smb2_setup_async_request, 314 .setup_async_request = smb2_setup_async_request,
@@ -322,6 +339,9 @@ struct smb_version_operations smb21_operations = {
322 .mkdir_setinfo = smb2_mkdir_setinfo, 339 .mkdir_setinfo = smb2_mkdir_setinfo,
323 .rmdir = smb2_rmdir, 340 .rmdir = smb2_rmdir,
324 .unlink = smb2_unlink, 341 .unlink = smb2_unlink,
342 .open = smb2_open_file,
343 .set_fid = smb2_set_fid,
344 .close = smb2_close_file,
325}; 345};
326 346
327struct smb_version_values smb21_values = { 347struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 62b3f17d0613..231e9701ab85 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -833,7 +833,8 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
833int 833int
834SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path, 834SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
835 u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access, 835 u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
836 __u32 create_disposition, __u32 file_attributes, __u32 create_options) 836 __u32 create_disposition, __u32 file_attributes, __u32 create_options,
837 struct smb2_file_all_info *buf)
837{ 838{
838 struct smb2_create_req *req; 839 struct smb2_create_req *req;
839 struct smb2_create_rsp *rsp; 840 struct smb2_create_rsp *rsp;
@@ -856,9 +857,9 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
856 if (rc) 857 if (rc)
857 return rc; 858 return rc;
858 859
859 if (enable_oplocks) 860 /* if (server->oplocks)
860 req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH; 861 req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
861 else 862 else */
862 req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE; 863 req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
863 req->ImpersonationLevel = IL_IMPERSONATION; 864 req->ImpersonationLevel = IL_IMPERSONATION;
864 req->DesiredAccess = cpu_to_le32(desired_access); 865 req->DesiredAccess = cpu_to_le32(desired_access);
@@ -906,6 +907,15 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
906 } 907 }
907 *persistent_fid = rsp->PersistentFileId; 908 *persistent_fid = rsp->PersistentFileId;
908 *volatile_fid = rsp->VolatileFileId; 909 *volatile_fid = rsp->VolatileFileId;
910
911 if (buf) {
912 memcpy(buf, &rsp->CreationTime, 32);
913 buf->AllocationSize = rsp->AllocationSize;
914 buf->EndOfFile = rsp->EndofFile;
915 buf->Attributes = rsp->FileAttributes;
916 buf->NumberOfLinks = cpu_to_le32(1);
917 buf->DeletePending = 0;
918 }
909creat_exit: 919creat_exit:
910 free_rsp_buf(resp_buftype, rsp); 920 free_rsp_buf(resp_buftype, rsp);
911 return rc; 921 return rc;
@@ -1019,10 +1029,10 @@ validate_and_copy_buf(unsigned int offset, unsigned int buffer_length,
1019 return 0; 1029 return 0;
1020} 1030}
1021 1031
1022int 1032static int
1023SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, 1033query_info(const unsigned int xid, struct cifs_tcon *tcon,
1024 u64 persistent_fid, u64 volatile_fid, 1034 u64 persistent_fid, u64 volatile_fid, u8 info_class,
1025 struct smb2_file_all_info *data) 1035 size_t output_len, size_t min_len, void *data)
1026{ 1036{
1027 struct smb2_query_info_req *req; 1037 struct smb2_query_info_req *req;
1028 struct smb2_query_info_rsp *rsp = NULL; 1038 struct smb2_query_info_rsp *rsp = NULL;
@@ -1044,14 +1054,13 @@ SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
1044 return rc; 1054 return rc;
1045 1055
1046 req->InfoType = SMB2_O_INFO_FILE; 1056 req->InfoType = SMB2_O_INFO_FILE;
1047 req->FileInfoClass = FILE_ALL_INFORMATION; 1057 req->FileInfoClass = info_class;
1048 req->PersistentFileId = persistent_fid; 1058 req->PersistentFileId = persistent_fid;
1049 req->VolatileFileId = volatile_fid; 1059 req->VolatileFileId = volatile_fid;
1050 /* 4 for rfc1002 length field and 1 for Buffer */ 1060 /* 4 for rfc1002 length field and 1 for Buffer */
1051 req->InputBufferOffset = 1061 req->InputBufferOffset =
1052 cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4); 1062 cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4);
1053 req->OutputBufferLength = 1063 req->OutputBufferLength = cpu_to_le32(output_len);
1054 cpu_to_le32(sizeof(struct smb2_file_all_info) + MAX_NAME * 2);
1055 1064
1056 iov[0].iov_base = (char *)req; 1065 iov[0].iov_base = (char *)req;
1057 /* 4 for rfc1002 length field */ 1066 /* 4 for rfc1002 length field */
@@ -1067,14 +1076,34 @@ SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
1067 1076
1068 rc = validate_and_copy_buf(le16_to_cpu(rsp->OutputBufferOffset), 1077 rc = validate_and_copy_buf(le16_to_cpu(rsp->OutputBufferOffset),
1069 le32_to_cpu(rsp->OutputBufferLength), 1078 le32_to_cpu(rsp->OutputBufferLength),
1070 &rsp->hdr, sizeof(struct smb2_file_all_info), 1079 &rsp->hdr, min_len, data);
1071 (char *)data);
1072 1080
1073qinf_exit: 1081qinf_exit:
1074 free_rsp_buf(resp_buftype, rsp); 1082 free_rsp_buf(resp_buftype, rsp);
1075 return rc; 1083 return rc;
1076} 1084}
1077 1085
1086int
1087SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
1088 u64 persistent_fid, u64 volatile_fid,
1089 struct smb2_file_all_info *data)
1090{
1091 return query_info(xid, tcon, persistent_fid, volatile_fid,
1092 FILE_ALL_INFORMATION,
1093 sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
1094 sizeof(struct smb2_file_all_info), data);
1095}
1096
1097int
1098SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
1099 u64 persistent_fid, u64 volatile_fid, __le64 *uniqueid)
1100{
1101 return query_info(xid, tcon, persistent_fid, volatile_fid,
1102 FILE_INTERNAL_INFORMATION,
1103 sizeof(struct smb2_file_internal_info),
1104 sizeof(struct smb2_file_internal_info), uniqueid);
1105}
1106
1078/* 1107/*
1079 * This is a no-op for now. We're not really interested in the reply, but 1108 * This is a no-op for now. We're not really interested in the reply, but
1080 * rather in the fact that the server sent one and that server->lstrp 1109 * rather in the fact that the server sent one and that server->lstrp
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 15dc8eea8273..0e962cbf8166 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -548,6 +548,10 @@ struct smb2_query_info_rsp {
548#define FILEID_GLOBAL_TX_DIRECTORY_INFORMATION 50 548#define FILEID_GLOBAL_TX_DIRECTORY_INFORMATION 50
549#define FILE_STANDARD_LINK_INFORMATION 54 549#define FILE_STANDARD_LINK_INFORMATION 54
550 550
551struct smb2_file_internal_info {
552 __le64 IndexNumber;
553} __packed; /* level 6 Query */
554
551/* 555/*
552 * This level 18, although with struct with same name is different from cifs 556 * This level 18, although with struct with same name is different from cifs
553 * level 0x107. Level 0x107 has an extra u64 between AccessFlags and 557 * level 0x107. Level 0x107 has an extra u64 between AccessFlags and
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index f4ac72799f70..624d344e1a57 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -48,6 +48,8 @@ extern int smb2_setup_async_request(struct TCP_Server_Info *server,
48 struct mid_q_entry **ret_mid); 48 struct mid_q_entry **ret_mid);
49extern void smb2_echo_request(struct work_struct *work); 49extern void smb2_echo_request(struct work_struct *work);
50 50
51extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
52 struct smb2_file_all_info *src);
51extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, 53extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
52 struct cifs_sb_info *cifs_sb, 54 struct cifs_sb_info *cifs_sb,
53 const char *full_path, FILE_ALL_INFO *data, 55 const char *full_path, FILE_ALL_INFO *data,
@@ -62,6 +64,12 @@ extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
62extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, 64extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
63 const char *name, struct cifs_sb_info *cifs_sb); 65 const char *name, struct cifs_sb_info *cifs_sb);
64 66
67extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
68 const char *full_path, int disposition,
69 int desired_access, int create_options,
70 struct cifs_fid *fid, __u32 *oplock,
71 FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb);
72
65/* 73/*
66 * SMB2 Worker functions - most of protocol specific implementation details 74 * SMB2 Worker functions - most of protocol specific implementation details
67 * are contained within these calls. 75 * are contained within these calls.
@@ -77,12 +85,16 @@ extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
77extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, 85extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
78 __le16 *path, u64 *persistent_fid, u64 *volatile_fid, 86 __le16 *path, u64 *persistent_fid, u64 *volatile_fid,
79 __u32 desired_access, __u32 create_disposition, 87 __u32 desired_access, __u32 create_disposition,
80 __u32 file_attributes, __u32 create_options); 88 __u32 file_attributes, __u32 create_options,
89 struct smb2_file_all_info *buf);
81extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, 90extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
82 u64 persistent_file_id, u64 volatile_file_id); 91 u64 persistent_file_id, u64 volatile_file_id);
83extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, 92extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
84 u64 persistent_file_id, u64 volatile_file_id, 93 u64 persistent_file_id, u64 volatile_file_id,
85 struct smb2_file_all_info *data); 94 struct smb2_file_all_info *data);
95extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
96 u64 persistent_fid, u64 volatile_fid,
97 __le64 *uniqueid);
86extern int SMB2_echo(struct TCP_Server_Info *server); 98extern int SMB2_echo(struct TCP_Server_Info *server);
87 99
88#endif /* _SMB2PROTO_H */ 100#endif /* _SMB2PROTO_H */