/source3/modules/vfs_readahead.c

https://github.com/theresahalloran/samba-tool-time-doc · C · 186 lines · 129 code · 20 blank · 37 comment · 13 complexity · 1c5d8fcdfaaf361f451998fec73b5124 MD5 · raw file

  1. /*
  2. * Copyright (c) Jeremy Allison 2007.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "includes.h"
  18. #include "system/filesys.h"
  19. #include "smbd/smbd.h"
  20. #if defined(HAVE_LINUX_READAHEAD) && ! defined(HAVE_READAHEAD_DECL)
  21. ssize_t readahead(int fd, off64_t offset, size_t count);
  22. #endif
  23. struct readahead_data {
  24. SMB_OFF_T off_bound;
  25. SMB_OFF_T len;
  26. bool didmsg;
  27. };
  28. /*
  29. * This module copes with Vista AIO read requests on Linux
  30. * by detecting the initial 0x80000 boundary reads and causing
  31. * the buffer cache to be filled in advance.
  32. */
  33. /*******************************************************************
  34. sendfile wrapper that does readahead/posix_fadvise.
  35. *******************************************************************/
  36. static ssize_t readahead_sendfile(struct vfs_handle_struct *handle,
  37. int tofd,
  38. files_struct *fromfsp,
  39. const DATA_BLOB *header,
  40. SMB_OFF_T offset,
  41. size_t count)
  42. {
  43. struct readahead_data *rhd = (struct readahead_data *)handle->data;
  44. if ( offset % rhd->off_bound == 0) {
  45. #if defined(HAVE_LINUX_READAHEAD)
  46. int err = readahead(fromfsp->fh->fd, offset, (size_t)rhd->len);
  47. DEBUG(10,("readahead_sendfile: readahead on fd %u, offset %llu, len %u returned %d\n",
  48. (unsigned int)fromfsp->fh->fd,
  49. (unsigned long long)offset,
  50. (unsigned int)rhd->len,
  51. err ));
  52. #elif defined(HAVE_POSIX_FADVISE)
  53. int err = posix_fadvise(fromfsp->fh->fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED);
  54. DEBUG(10,("readahead_sendfile: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
  55. (unsigned int)fromfsp->fh->fd,
  56. (unsigned long long)offset,
  57. (unsigned int)rhd->len,
  58. err ));
  59. #else
  60. if (!rhd->didmsg) {
  61. DEBUG(0,("readahead_sendfile: no readahead on this platform\n"));
  62. rhd->didmsg = True;
  63. }
  64. #endif
  65. }
  66. return SMB_VFS_NEXT_SENDFILE(handle,
  67. tofd,
  68. fromfsp,
  69. header,
  70. offset,
  71. count);
  72. }
  73. /*******************************************************************
  74. pread wrapper that does readahead/posix_fadvise.
  75. *******************************************************************/
  76. static ssize_t readahead_pread(vfs_handle_struct *handle,
  77. files_struct *fsp,
  78. void *data,
  79. size_t count,
  80. SMB_OFF_T offset)
  81. {
  82. struct readahead_data *rhd = (struct readahead_data *)handle->data;
  83. if ( offset % rhd->off_bound == 0) {
  84. #if defined(HAVE_LINUX_READAHEAD)
  85. int err = readahead(fsp->fh->fd, offset, (size_t)rhd->len);
  86. DEBUG(10,("readahead_pread: readahead on fd %u, offset %llu, len %u returned %d\n",
  87. (unsigned int)fsp->fh->fd,
  88. (unsigned long long)offset,
  89. (unsigned int)rhd->len,
  90. err ));
  91. #elif defined(HAVE_POSIX_FADVISE)
  92. int err = posix_fadvise(fsp->fh->fd, offset, (off_t)rhd->len, POSIX_FADV_WILLNEED);
  93. DEBUG(10,("readahead_pread: posix_fadvise on fd %u, offset %llu, len %u returned %d\n",
  94. (unsigned int)fsp->fh->fd,
  95. (unsigned long long)offset,
  96. (unsigned int)rhd->len,
  97. err ));
  98. #else
  99. if (!rhd->didmsg) {
  100. DEBUG(0,("readahead_pread: no readahead on this platform\n"));
  101. rhd->didmsg = True;
  102. }
  103. #endif
  104. }
  105. return SMB_VFS_NEXT_PREAD(handle, fsp, data, count, offset);
  106. }
  107. /*******************************************************************
  108. Directly called from main smbd when freeing handle.
  109. *******************************************************************/
  110. static void free_readahead_data(void **pptr)
  111. {
  112. SAFE_FREE(*pptr);
  113. }
  114. /*******************************************************************
  115. Allocate the handle specific data so we don't call the expensive
  116. conv_str_size function for each sendfile/pread.
  117. *******************************************************************/
  118. static int readahead_connect(struct vfs_handle_struct *handle,
  119. const char *service,
  120. const char *user)
  121. {
  122. struct readahead_data *rhd;
  123. int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
  124. if (ret < 0) {
  125. return ret;
  126. }
  127. rhd = SMB_MALLOC_P(struct readahead_data);
  128. if (!rhd) {
  129. SMB_VFS_NEXT_DISCONNECT(handle);
  130. DEBUG(0,("readahead_connect: out of memory\n"));
  131. return -1;
  132. }
  133. ZERO_STRUCTP(rhd);
  134. rhd->didmsg = False;
  135. rhd->off_bound = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
  136. "readahead",
  137. "offset",
  138. NULL));
  139. if (rhd->off_bound == 0) {
  140. rhd->off_bound = 0x80000;
  141. }
  142. rhd->len = conv_str_size(lp_parm_const_string(SNUM(handle->conn),
  143. "readahead",
  144. "length",
  145. NULL));
  146. if (rhd->len == 0) {
  147. rhd->len = rhd->off_bound;
  148. }
  149. handle->data = (void *)rhd;
  150. handle->free_data = free_readahead_data;
  151. return 0;
  152. }
  153. static struct vfs_fn_pointers vfs_readahead_fns = {
  154. .sendfile = readahead_sendfile,
  155. .pread = readahead_pread,
  156. .connect_fn = readahead_connect
  157. };
  158. /*******************************************************************
  159. Module initialization boilerplate.
  160. *******************************************************************/
  161. NTSTATUS vfs_readahead_init(void);
  162. NTSTATUS vfs_readahead_init(void)
  163. {
  164. return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "readahead",
  165. &vfs_readahead_fns);
  166. }