ksmbd_work.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2019 Samsung Electronics Co., Ltd.
  4. */
  5. #include <linux/list.h>
  6. #include <linux/mm.h>
  7. #include <linux/slab.h>
  8. #include <linux/workqueue.h>
  9. #include "server.h"
  10. #include "connection.h"
  11. #include "ksmbd_work.h"
  12. #include "mgmt/ksmbd_ida.h"
  13. static struct kmem_cache *work_cache;
  14. static struct workqueue_struct *ksmbd_wq;
  15. struct ksmbd_work *ksmbd_alloc_work_struct(void)
  16. {
  17. struct ksmbd_work *work = kmem_cache_zalloc(work_cache, KSMBD_DEFAULT_GFP);
  18. if (work) {
  19. work->compound_fid = KSMBD_NO_FID;
  20. work->compound_pfid = KSMBD_NO_FID;
  21. INIT_LIST_HEAD(&work->request_entry);
  22. INIT_LIST_HEAD(&work->async_request_entry);
  23. INIT_LIST_HEAD(&work->fp_entry);
  24. INIT_LIST_HEAD(&work->aux_read_list);
  25. work->iov_alloc_cnt = 4;
  26. work->iov = kcalloc(work->iov_alloc_cnt, sizeof(struct kvec),
  27. KSMBD_DEFAULT_GFP);
  28. if (!work->iov) {
  29. kmem_cache_free(work_cache, work);
  30. work = NULL;
  31. }
  32. }
  33. return work;
  34. }
  35. void ksmbd_free_work_struct(struct ksmbd_work *work)
  36. {
  37. struct aux_read *ar, *tmp;
  38. WARN_ON(work->saved_cred != NULL);
  39. kvfree(work->response_buf);
  40. list_for_each_entry_safe(ar, tmp, &work->aux_read_list, entry) {
  41. kvfree(ar->buf);
  42. list_del(&ar->entry);
  43. kfree(ar);
  44. }
  45. kfree(work->tr_buf);
  46. kvfree(work->request_buf);
  47. kfree(work->iov);
  48. if (work->async_id)
  49. ksmbd_release_id(&work->conn->async_ida, work->async_id);
  50. kmem_cache_free(work_cache, work);
  51. }
  52. void ksmbd_work_pool_destroy(void)
  53. {
  54. kmem_cache_destroy(work_cache);
  55. }
  56. int ksmbd_work_pool_init(void)
  57. {
  58. work_cache = kmem_cache_create("ksmbd_work_cache",
  59. sizeof(struct ksmbd_work), 0,
  60. SLAB_HWCACHE_ALIGN, NULL);
  61. if (!work_cache)
  62. return -ENOMEM;
  63. return 0;
  64. }
  65. int ksmbd_workqueue_init(void)
  66. {
  67. ksmbd_wq = alloc_workqueue("ksmbd-io", 0, 0);
  68. if (!ksmbd_wq)
  69. return -ENOMEM;
  70. return 0;
  71. }
  72. void ksmbd_workqueue_destroy(void)
  73. {
  74. destroy_workqueue(ksmbd_wq);
  75. ksmbd_wq = NULL;
  76. }
  77. bool ksmbd_queue_work(struct ksmbd_work *work)
  78. {
  79. return queue_work(ksmbd_wq, &work->work);
  80. }
  81. static inline void __ksmbd_iov_pin(struct ksmbd_work *work, void *ib,
  82. unsigned int ib_len)
  83. {
  84. work->iov[++work->iov_idx].iov_base = ib;
  85. work->iov[work->iov_idx].iov_len = ib_len;
  86. work->iov_cnt++;
  87. }
  88. static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
  89. void *aux_buf, unsigned int aux_size)
  90. {
  91. struct aux_read *ar = NULL;
  92. int need_iov_cnt = 1;
  93. if (aux_size) {
  94. need_iov_cnt++;
  95. ar = kmalloc(sizeof(struct aux_read), KSMBD_DEFAULT_GFP);
  96. if (!ar)
  97. return -ENOMEM;
  98. }
  99. if (work->iov_alloc_cnt < work->iov_cnt + need_iov_cnt) {
  100. struct kvec *new;
  101. work->iov_alloc_cnt += 4;
  102. new = krealloc(work->iov,
  103. sizeof(struct kvec) * work->iov_alloc_cnt,
  104. KSMBD_DEFAULT_GFP | __GFP_ZERO);
  105. if (!new) {
  106. kfree(ar);
  107. work->iov_alloc_cnt -= 4;
  108. return -ENOMEM;
  109. }
  110. work->iov = new;
  111. }
  112. /* Plus rfc_length size on first iov */
  113. if (!work->iov_idx) {
  114. work->iov[work->iov_idx].iov_base = work->response_buf;
  115. *(__be32 *)work->iov[0].iov_base = 0;
  116. work->iov[work->iov_idx].iov_len = 4;
  117. work->iov_cnt++;
  118. }
  119. __ksmbd_iov_pin(work, ib, len);
  120. inc_rfc1001_len(work->iov[0].iov_base, len);
  121. if (aux_size) {
  122. __ksmbd_iov_pin(work, aux_buf, aux_size);
  123. inc_rfc1001_len(work->iov[0].iov_base, aux_size);
  124. ar->buf = aux_buf;
  125. list_add(&ar->entry, &work->aux_read_list);
  126. }
  127. return 0;
  128. }
  129. int ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len)
  130. {
  131. return __ksmbd_iov_pin_rsp(work, ib, len, NULL, 0);
  132. }
  133. int ksmbd_iov_pin_rsp_read(struct ksmbd_work *work, void *ib, int len,
  134. void *aux_buf, unsigned int aux_size)
  135. {
  136. return __ksmbd_iov_pin_rsp(work, ib, len, aux_buf, aux_size);
  137. }
  138. int allocate_interim_rsp_buf(struct ksmbd_work *work)
  139. {
  140. work->response_buf = kzalloc(MAX_CIFS_SMALL_BUFFER_SIZE, KSMBD_DEFAULT_GFP);
  141. if (!work->response_buf)
  142. return -ENOMEM;
  143. work->response_sz = MAX_CIFS_SMALL_BUFFER_SIZE;
  144. return 0;
  145. }