Mirror of strace – the linux syscall tracer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

file_ioctl.c 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * Copyright (c) 2016 Jeff Mahoney <jeffm@suse.com>
  3. * Copyright (c) 2016-2018 The strace developers.
  4. * All rights reserved.
  5. *
  6. * SPDX-License-Identifier: LGPL-2.1-or-later
  7. */
  8. #include "defs.h"
  9. #include <linux/ioctl.h>
  10. #include <linux/fs.h>
  11. #ifdef HAVE_LINUX_FIEMAP_H
  12. # include <linux/fiemap.h>
  13. # include "xlat/fiemap_flags.h"
  14. # include "xlat/fiemap_extent_flags.h"
  15. #endif
  16. #ifndef FICLONE
  17. # define FICLONE _IOW(0x94, 9, int)
  18. #endif
  19. #ifndef FICLONERANGE
  20. # define FICLONERANGE _IOW(0x94, 13, struct file_clone_range)
  21. struct file_clone_range {
  22. int64_t src_fd;
  23. uint64_t src_offset;
  24. uint64_t src_length;
  25. uint64_t dest_offset;
  26. };
  27. #endif
  28. #ifndef FIDEDUPERANGE
  29. # define FIDEDUPERANGE _IOWR(0x94, 54, struct file_dedupe_range)
  30. struct file_dedupe_range_info {
  31. int64_t dest_fd; /* in - destination file */
  32. uint64_t dest_offset; /* in - start of extent in destination */
  33. uint64_t bytes_deduped; /* out - total # of bytes we were able
  34. * to dedupe from this file. */
  35. /* status of this dedupe operation:
  36. * < 0 for error
  37. * == FILE_DEDUPE_RANGE_SAME if dedupe succeeds
  38. * == FILE_DEDUPE_RANGE_DIFFERS if data differs
  39. */
  40. int32_t status; /* out - see above description */
  41. uint32_t reserved; /* must be zero */
  42. };
  43. struct file_dedupe_range {
  44. uint64_t src_offset; /* in - start of extent in source */
  45. uint64_t src_length; /* in - length of extent */
  46. uint16_t dest_count; /* in - total elements in info array */
  47. uint16_t reserved1; /* must be zero */
  48. uint32_t reserved2; /* must be zero */
  49. struct file_dedupe_range_info info[0];
  50. };
  51. #endif
  52. static bool
  53. print_file_dedupe_range_info(struct tcb *tcp, void *elem_buf,
  54. size_t elem_size, void *data)
  55. {
  56. const struct file_dedupe_range_info *info = elem_buf;
  57. unsigned int *count = data;
  58. if (count) {
  59. if (*count == 0) {
  60. tprints("...");
  61. return false;
  62. }
  63. --*count;
  64. }
  65. if (entering(tcp)) {
  66. tprints("{dest_fd=");
  67. printfd(tcp, info->dest_fd);
  68. tprintf(", dest_offset=%" PRIu64 "}",
  69. (uint64_t) info->dest_offset);
  70. } else {
  71. tprintf("{bytes_deduped=%" PRIu64 ", status=%d}",
  72. (uint64_t) info->bytes_deduped, info->status);
  73. }
  74. return true;
  75. }
  76. #ifdef HAVE_LINUX_FIEMAP_H
  77. static bool
  78. print_fiemap_extent(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
  79. {
  80. const struct fiemap_extent *fe = elem_buf;
  81. tprintf("{fe_logical=%" PRI__u64
  82. ", fe_physical=%" PRI__u64
  83. ", fe_length=%" PRI__u64 ", ",
  84. fe->fe_logical, fe->fe_physical, fe->fe_length);
  85. printflags64(fiemap_extent_flags, fe->fe_flags,
  86. "FIEMAP_EXTENT_???");
  87. tprints("}");
  88. return true;
  89. }
  90. #endif /* HAVE_LINUX_FIEMAP_H */
  91. int
  92. file_ioctl(struct tcb *const tcp, const unsigned int code,
  93. const kernel_ulong_t arg)
  94. {
  95. switch (code) {
  96. case FICLONE: /* W */
  97. tprintf(", %d", (int) arg);
  98. break;
  99. case FICLONERANGE: { /* W */
  100. struct file_clone_range args;
  101. tprints(", ");
  102. if (umove_or_printaddr(tcp, arg, &args))
  103. break;
  104. tprints("{src_fd=");
  105. printfd(tcp, args.src_fd);
  106. tprintf(", src_offset=%" PRIu64
  107. ", src_length=%" PRIu64
  108. ", dest_offset=%" PRIu64 "}",
  109. (uint64_t) args.src_offset,
  110. (uint64_t) args.src_length,
  111. (uint64_t) args.dest_offset);
  112. break;
  113. }
  114. case FIDEDUPERANGE: { /* RW */
  115. struct file_dedupe_range args;
  116. struct file_dedupe_range_info info;
  117. unsigned int *limit = NULL;
  118. unsigned int count = 2;
  119. bool rc;
  120. if (entering(tcp))
  121. tprints(", ");
  122. else if (syserror(tcp))
  123. break;
  124. else
  125. tprints(" => ");
  126. if (umove_or_printaddr(tcp, arg, &args))
  127. break;
  128. tprints("{");
  129. if (entering(tcp)) {
  130. tprintf("src_offset=%" PRIu64
  131. ", src_length=%" PRIu64
  132. ", dest_count=%hu, ",
  133. (uint64_t) args.src_offset,
  134. (uint64_t) args.src_length,
  135. (uint16_t) args.dest_count);
  136. }
  137. tprints("info=");
  138. /* Limit how many elements we print in abbrev mode. */
  139. if (abbrev(tcp) && args.dest_count > count)
  140. limit = &count;
  141. rc = print_array(tcp, arg + offsetof(typeof(args), info),
  142. args.dest_count, &info, sizeof(info),
  143. tfetch_mem,
  144. print_file_dedupe_range_info, limit);
  145. tprints("}");
  146. if (!rc || exiting(tcp))
  147. break;
  148. return 0;
  149. }
  150. #ifdef HAVE_LINUX_FIEMAP_H
  151. case FS_IOC_FIEMAP: {
  152. struct fiemap args;
  153. if (entering(tcp))
  154. tprints(", ");
  155. else if (syserror(tcp))
  156. break;
  157. else
  158. tprints(" => ");
  159. if (umove_or_printaddr(tcp, arg, &args))
  160. break;
  161. if (entering(tcp)) {
  162. tprintf("{fm_start=%" PRI__u64 ", "
  163. "fm_length=%" PRI__u64 ", "
  164. "fm_flags=",
  165. args.fm_start, args.fm_length);
  166. printflags64(fiemap_flags, args.fm_flags,
  167. "FIEMAP_FLAG_???");
  168. tprintf(", fm_extent_count=%u}", args.fm_extent_count);
  169. return 0;
  170. }
  171. tprints("{fm_flags=");
  172. printflags64(fiemap_flags, args.fm_flags,
  173. "FIEMAP_FLAG_???");
  174. tprintf(", fm_mapped_extents=%u",
  175. args.fm_mapped_extents);
  176. if (abbrev(tcp)) {
  177. tprints(", ...");
  178. } else {
  179. struct fiemap_extent fe;
  180. tprints(", fm_extents=");
  181. print_array(tcp,
  182. arg + offsetof(typeof(args), fm_extents),
  183. args.fm_mapped_extents, &fe, sizeof(fe),
  184. tfetch_mem,
  185. print_fiemap_extent, 0);
  186. }
  187. tprints("}");
  188. break;
  189. }
  190. #endif /* HAVE_LINUX_FIEMAP_H */
  191. default:
  192. return RVAL_DECODED;
  193. };
  194. return RVAL_IOCTL_DECODED;
  195. }