smb2ops.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * SMB2 version specific operations
  3. *
  4. * Copyright (c) 2012, Jeff Layton <jlayton@redhat.com>
  5. *
  6. * This library is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License v2 as published
  8. * by the Free Software Foundation.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  13. * the GNU Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public License
  16. * along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #include "cifsglob.h"
  20. #include "smb2pdu.h"
  21. #include "smb2proto.h"
  22. #include "cifsproto.h"
  23. #include "cifs_debug.h"
  24. static int
  25. change_conf(struct TCP_Server_Info *server)
  26. {
  27. server->credits += server->echo_credits + server->oplock_credits;
  28. server->oplock_credits = server->echo_credits = 0;
  29. switch (server->credits) {
  30. case 0:
  31. return -1;
  32. case 1:
  33. server->echoes = false;
  34. server->oplocks = false;
  35. cERROR(1, "disabling echoes and oplocks");
  36. break;
  37. case 2:
  38. server->echoes = true;
  39. server->oplocks = false;
  40. server->echo_credits = 1;
  41. cFYI(1, "disabling oplocks");
  42. break;
  43. default:
  44. server->echoes = true;
  45. server->oplocks = true;
  46. server->echo_credits = 1;
  47. server->oplock_credits = 1;
  48. }
  49. server->credits -= server->echo_credits + server->oplock_credits;
  50. return 0;
  51. }
  52. static void
  53. smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
  54. const int optype)
  55. {
  56. int *val, rc = 0;
  57. spin_lock(&server->req_lock);
  58. val = server->ops->get_credits_field(server, optype);
  59. *val += add;
  60. server->in_flight--;
  61. if (server->in_flight == 0 && (optype & CIFS_OP_MASK) != CIFS_NEG_OP)
  62. rc = change_conf(server);
  63. spin_unlock(&server->req_lock);
  64. wake_up(&server->request_q);
  65. if (rc)
  66. cifs_reconnect(server);
  67. }
  68. static void
  69. smb2_set_credits(struct TCP_Server_Info *server, const int val)
  70. {
  71. spin_lock(&server->req_lock);
  72. server->credits = val;
  73. spin_unlock(&server->req_lock);
  74. }
  75. static int *
  76. smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
  77. {
  78. switch (optype) {
  79. case CIFS_ECHO_OP:
  80. return &server->echo_credits;
  81. case CIFS_OBREAK_OP:
  82. return &server->oplock_credits;
  83. default:
  84. return &server->credits;
  85. }
  86. }
  87. static unsigned int
  88. smb2_get_credits(struct mid_q_entry *mid)
  89. {
  90. return le16_to_cpu(((struct smb2_hdr *)mid->resp_buf)->CreditRequest);
  91. }
  92. static __u64
  93. smb2_get_next_mid(struct TCP_Server_Info *server)
  94. {
  95. __u64 mid;
  96. /* for SMB2 we need the current value */
  97. spin_lock(&GlobalMid_Lock);
  98. mid = server->CurrentMid++;
  99. spin_unlock(&GlobalMid_Lock);
  100. return mid;
  101. }
  102. static struct mid_q_entry *
  103. smb2_find_mid(struct TCP_Server_Info *server, char *buf)
  104. {
  105. struct mid_q_entry *mid;
  106. struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
  107. spin_lock(&GlobalMid_Lock);
  108. list_for_each_entry(mid, &server->pending_mid_q, qhead) {
  109. if ((mid->mid == hdr->MessageId) &&
  110. (mid->mid_state == MID_REQUEST_SUBMITTED) &&
  111. (mid->command == hdr->Command)) {
  112. spin_unlock(&GlobalMid_Lock);
  113. return mid;
  114. }
  115. }
  116. spin_unlock(&GlobalMid_Lock);
  117. return NULL;
  118. }
  119. static void
  120. smb2_dump_detail(void *buf)
  121. {
  122. #ifdef CONFIG_CIFS_DEBUG2
  123. struct smb2_hdr *smb = (struct smb2_hdr *)buf;
  124. cERROR(1, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d",
  125. smb->Command, smb->Status, smb->Flags, smb->MessageId,
  126. smb->ProcessId);
  127. cERROR(1, "smb buf %p len %u", smb, smb2_calc_size(smb));
  128. #endif
  129. }
  130. static bool
  131. smb2_need_neg(struct TCP_Server_Info *server)
  132. {
  133. return server->max_read == 0;
  134. }
  135. static int
  136. smb2_negotiate(const unsigned int xid, struct cifs_ses *ses)
  137. {
  138. int rc;
  139. ses->server->CurrentMid = 0;
  140. rc = SMB2_negotiate(xid, ses);
  141. /* BB we probably don't need to retry with modern servers */
  142. if (rc == -EAGAIN)
  143. rc = -EHOSTDOWN;
  144. return rc;
  145. }
  146. static int
  147. smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
  148. struct cifs_sb_info *cifs_sb, const char *full_path)
  149. {
  150. int rc;
  151. __u64 persistent_fid, volatile_fid;
  152. __le16 *utf16_path;
  153. utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
  154. if (!utf16_path)
  155. return -ENOMEM;
  156. rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
  157. FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0);
  158. if (rc) {
  159. kfree(utf16_path);
  160. return rc;
  161. }
  162. rc = SMB2_close(xid, tcon, persistent_fid, volatile_fid);
  163. kfree(utf16_path);
  164. return rc;
  165. }
  166. static int
  167. smb2_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
  168. struct cifs_sb_info *cifs_sb, const char *full_path,
  169. u64 *uniqueid, FILE_ALL_INFO *data)
  170. {
  171. *uniqueid = le64_to_cpu(data->IndexNumber);
  172. return 0;
  173. }
  174. static char *
  175. smb2_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
  176. struct cifs_tcon *tcon)
  177. {
  178. int pplen = vol->prepath ? strlen(vol->prepath) : 0;
  179. char *full_path = NULL;
  180. /* if no prefix path, simply set path to the root of share to "" */
  181. if (pplen == 0) {
  182. full_path = kzalloc(2, GFP_KERNEL);
  183. return full_path;
  184. }
  185. cERROR(1, "prefixpath is not supported for SMB2 now");
  186. return NULL;
  187. }
  188. static bool
  189. smb2_can_echo(struct TCP_Server_Info *server)
  190. {
  191. return server->echoes;
  192. }
  193. static void
  194. smb2_clear_stats(struct cifs_tcon *tcon)
  195. {
  196. #ifdef CONFIG_CIFS_STATS
  197. int i;
  198. for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
  199. atomic_set(&tcon->stats.smb2_stats.smb2_com_sent[i], 0);
  200. atomic_set(&tcon->stats.smb2_stats.smb2_com_failed[i], 0);
  201. }
  202. #endif
  203. }
  204. static void
  205. smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
  206. {
  207. #ifdef CONFIG_CIFS_STATS
  208. atomic_t *sent = tcon->stats.smb2_stats.smb2_com_sent;
  209. atomic_t *failed = tcon->stats.smb2_stats.smb2_com_failed;
  210. seq_printf(m, "\nNegotiates: %d sent %d failed",
  211. atomic_read(&sent[SMB2_NEGOTIATE_HE]),
  212. atomic_read(&failed[SMB2_NEGOTIATE_HE]));
  213. seq_printf(m, "\nSessionSetups: %d sent %d failed",
  214. atomic_read(&sent[SMB2_SESSION_SETUP_HE]),
  215. atomic_read(&failed[SMB2_SESSION_SETUP_HE]));
  216. #define SMB2LOGOFF 0x0002 /* trivial request/resp */
  217. seq_printf(m, "\nLogoffs: %d sent %d failed",
  218. atomic_read(&sent[SMB2_LOGOFF_HE]),
  219. atomic_read(&failed[SMB2_LOGOFF_HE]));
  220. seq_printf(m, "\nTreeConnects: %d sent %d failed",
  221. atomic_read(&sent[SMB2_TREE_CONNECT_HE]),
  222. atomic_read(&failed[SMB2_TREE_CONNECT_HE]));
  223. seq_printf(m, "\nTreeDisconnects: %d sent %d failed",
  224. atomic_read(&sent[SMB2_TREE_DISCONNECT_HE]),
  225. atomic_read(&failed[SMB2_TREE_DISCONNECT_HE]));
  226. seq_printf(m, "\nCreates: %d sent %d failed",
  227. atomic_read(&sent[SMB2_CREATE_HE]),
  228. atomic_read(&failed[SMB2_CREATE_HE]));
  229. seq_printf(m, "\nCloses: %d sent %d failed",
  230. atomic_read(&sent[SMB2_CLOSE_HE]),
  231. atomic_read(&failed[SMB2_CLOSE_HE]));
  232. seq_printf(m, "\nFlushes: %d sent %d failed",
  233. atomic_read(&sent[SMB2_FLUSH_HE]),
  234. atomic_read(&failed[SMB2_FLUSH_HE]));
  235. seq_printf(m, "\nReads: %d sent %d failed",
  236. atomic_read(&sent[SMB2_READ_HE]),
  237. atomic_read(&failed[SMB2_READ_HE]));
  238. seq_printf(m, "\nWrites: %d sent %d failed",
  239. atomic_read(&sent[SMB2_WRITE_HE]),
  240. atomic_read(&failed[SMB2_WRITE_HE]));
  241. seq_printf(m, "\nLocks: %d sent %d failed",
  242. atomic_read(&sent[SMB2_LOCK_HE]),
  243. atomic_read(&failed[SMB2_LOCK_HE]));
  244. seq_printf(m, "\nIOCTLs: %d sent %d failed",
  245. atomic_read(&sent[SMB2_IOCTL_HE]),
  246. atomic_read(&failed[SMB2_IOCTL_HE]));
  247. seq_printf(m, "\nCancels: %d sent %d failed",
  248. atomic_read(&sent[SMB2_CANCEL_HE]),
  249. atomic_read(&failed[SMB2_CANCEL_HE]));
  250. seq_printf(m, "\nEchos: %d sent %d failed",
  251. atomic_read(&sent[SMB2_ECHO_HE]),
  252. atomic_read(&failed[SMB2_ECHO_HE]));
  253. seq_printf(m, "\nQueryDirectories: %d sent %d failed",
  254. atomic_read(&sent[SMB2_QUERY_DIRECTORY_HE]),
  255. atomic_read(&failed[SMB2_QUERY_DIRECTORY_HE]));
  256. seq_printf(m, "\nChangeNotifies: %d sent %d failed",
  257. atomic_read(&sent[SMB2_CHANGE_NOTIFY_HE]),
  258. atomic_read(&failed[SMB2_CHANGE_NOTIFY_HE]));
  259. seq_printf(m, "\nQueryInfos: %d sent %d failed",
  260. atomic_read(&sent[SMB2_QUERY_INFO_HE]),
  261. atomic_read(&failed[SMB2_QUERY_INFO_HE]));
  262. seq_printf(m, "\nSetInfos: %d sent %d failed",
  263. atomic_read(&sent[SMB2_SET_INFO_HE]),
  264. atomic_read(&failed[SMB2_SET_INFO_HE]));
  265. seq_printf(m, "\nOplockBreaks: %d sent %d failed",
  266. atomic_read(&sent[SMB2_OPLOCK_BREAK_HE]),
  267. atomic_read(&failed[SMB2_OPLOCK_BREAK_HE]));
  268. #endif
  269. }
  270. struct smb_version_operations smb21_operations = {
  271. .setup_request = smb2_setup_request,
  272. .setup_async_request = smb2_setup_async_request,
  273. .check_receive = smb2_check_receive,
  274. .add_credits = smb2_add_credits,
  275. .set_credits = smb2_set_credits,
  276. .get_credits_field = smb2_get_credits_field,
  277. .get_credits = smb2_get_credits,
  278. .get_next_mid = smb2_get_next_mid,
  279. .find_mid = smb2_find_mid,
  280. .check_message = smb2_check_message,
  281. .dump_detail = smb2_dump_detail,
  282. .clear_stats = smb2_clear_stats,
  283. .print_stats = smb2_print_stats,
  284. .need_neg = smb2_need_neg,
  285. .negotiate = smb2_negotiate,
  286. .sess_setup = SMB2_sess_setup,
  287. .logoff = SMB2_logoff,
  288. .tree_connect = SMB2_tcon,
  289. .tree_disconnect = SMB2_tdis,
  290. .is_path_accessible = smb2_is_path_accessible,
  291. .can_echo = smb2_can_echo,
  292. .echo = SMB2_echo,
  293. .query_path_info = smb2_query_path_info,
  294. .get_srv_inum = smb2_get_srv_inum,
  295. .build_path_to_root = smb2_build_path_to_root,
  296. .mkdir = smb2_mkdir,
  297. .mkdir_setinfo = smb2_mkdir_setinfo,
  298. .rmdir = smb2_rmdir,
  299. };
  300. struct smb_version_values smb21_values = {
  301. .version_string = SMB21_VERSION_STRING,
  302. .header_size = sizeof(struct smb2_hdr),
  303. .max_header_size = MAX_SMB2_HDR_SIZE,
  304. .lock_cmd = SMB2_LOCK,
  305. .cap_unix = 0,
  306. .cap_nt_find = SMB2_NT_FIND,
  307. .cap_large_files = SMB2_LARGE_FILES,
  308. };