*/
#include "defs.h"
-#include <sys/ioctl.h>
+#include <linux/ioctl.h>
#include <linux/fs.h>
+
+#ifdef HAVE_LINUX_FIEMAP_H
+# include <linux/fiemap.h>
+# include "xlat/fiemap_flags.h"
+# include "xlat/fiemap_extent_flags.h"
+#endif
+
#ifndef FICLONE
-#define FICLONE _IOW(0x94, 9, int)
+# define FICLONE _IOW(0x94, 9, int)
#endif
#ifndef FICLONERANGE
-#define FICLONERANGE _IOW(0x94, 13, struct file_clone_range)
+# define FICLONERANGE _IOW(0x94, 13, struct file_clone_range)
struct file_clone_range {
int64_t src_fd;
uint64_t src_offset;
#endif
#ifndef FIDEDUPERANGE
-#define FIDEDUPERANGE _IOWR(0x94, 54, struct file_dedupe_range)
+# define FIDEDUPERANGE _IOWR(0x94, 54, struct file_dedupe_range)
struct file_dedupe_range_info {
int64_t dest_fd; /* in - destination file */
uint64_t dest_offset; /* in - start of extent in destination */
};
#endif
+static bool
+print_file_dedupe_range_info(struct tcb *tcp, void *elem_buf,
+ size_t elem_size, void *data)
+{
+ const struct file_dedupe_range_info *info = elem_buf;
+ unsigned int *count = data;
+
+ if (count) {
+ if (*count == 0) {
+ tprints("...");
+ return false;
+ }
+ --*count;
+ }
+
+ if (entering(tcp)) {
+ tprints("{dest_fd=");
+ printfd(tcp, info->dest_fd);
+ tprintf(", dest_offset=%" PRIu64 "}",
+ (uint64_t) info->dest_offset);
+ } else {
+ tprintf("{bytes_deduped=%" PRIu64 ", status=%d}",
+ (uint64_t) info->bytes_deduped, info->status);
+ }
+
+ return true;
+}
+
+#ifdef HAVE_LINUX_FIEMAP_H
+static bool
+print_fiemap_extent(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
+{
+ const struct fiemap_extent *fe = elem_buf;
+
+ tprintf("{fe_logical=%" PRI__u64
+ ", fe_physical=%" PRI__u64
+ ", fe_length=%" PRI__u64 ", ",
+ fe->fe_logical, fe->fe_physical, fe->fe_length);
+
+ printflags64(fiemap_extent_flags, fe->fe_flags,
+ "FIEMAP_EXTENT_???");
+ tprints("}");
+
+ return true;
+}
+#endif /* HAVE_LINUX_FIEMAP_H */
+
int
-file_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
+file_ioctl(struct tcb *const tcp, const unsigned int code,
+ const kernel_ulong_t arg)
{
switch (code) {
- /* take a signed int */
case FICLONE: /* W */
- tprintf(", %d", (int)arg);
+ tprintf(", %d", (int) arg);
break;
case FICLONERANGE: { /* W */
struct file_clone_range args;
tprints(", ");
-
if (umove_or_printaddr(tcp, arg, &args))
break;
- tprintf("{src_fd=%" PRIi64 ", "
- "src_offset=%" PRIu64 ", "
- "src_length=%" PRIu64 ", "
- "dest_offset=%" PRIu64 "}",
- (int64_t)args.src_fd, (uint64_t)args.src_offset,
- (uint64_t)args.src_length, (uint64_t)args.dest_offset);
+ tprints("{src_fd=");
+ printfd(tcp, args.src_fd);
+ tprintf(", src_offset=%" PRIu64
+ ", src_length=%" PRIu64
+ ", dest_offset=%" PRIu64 "}",
+ (uint64_t) args.src_offset,
+ (uint64_t) args.src_length,
+ (uint64_t) args.dest_offset);
break;
}
case FIDEDUPERANGE: { /* RW */
struct file_dedupe_range args;
- uint64_t info_addr;
- uint16_t i;
+ struct file_dedupe_range_info info;
+ unsigned int *limit = NULL;
+ unsigned int count = 2;
+ bool rc;
if (entering(tcp))
tprints(", ");
if (umove_or_printaddr(tcp, arg, &args))
break;
+ tprints("{");
if (entering(tcp)) {
- tprintf("{src_offset=%" PRIu64 ", "
- "src_length=%" PRIu64 ", "
- "dest_count=%hu, info=",
- (uint64_t)args.src_offset,
- (uint64_t)args.src_length,
- (uint16_t)args.dest_count);
- } else
- tprints("{info=");
+ tprintf("src_offset=%" PRIu64
+ ", src_length=%" PRIu64
+ ", dest_count=%hu, ",
+ (uint64_t) args.src_offset,
+ (uint64_t) args.src_length,
+ (uint16_t) args.dest_count);
+ }
+
+ tprints("info=");
+
+ /* Limit how many elements we print in abbrev mode. */
+ if (abbrev(tcp) && args.dest_count > count)
+ limit = &count;
+
+ rc = print_array(tcp, arg + offsetof(typeof(args), info),
+ args.dest_count, &info, sizeof(info),
+ umoven_or_printaddr,
+ print_file_dedupe_range_info, limit);
+ tprints("}");
+ if (!rc || exiting(tcp))
+ break;
+
+ return 0;
+ }
+
+#ifdef HAVE_LINUX_FIEMAP_H
+ case FS_IOC_FIEMAP: {
+ struct fiemap args;
+
+ if (entering(tcp))
+ tprints(", ");
+ else if (syserror(tcp))
+ break;
+ else
+ tprints(" => ");
+
+ if (umove_or_printaddr(tcp, arg, &args))
+ break;
+
+ if (entering(tcp)) {
+ tprintf("{fm_start=%" PRI__u64 ", "
+ "fm_length=%" PRI__u64 ", "
+ "fm_flags=",
+ args.fm_start, args.fm_length);
+ printflags64(fiemap_flags, args.fm_flags,
+ "FIEMAP_FLAG_???");
+ tprintf(", fm_extent_count=%u}", args.fm_extent_count);
+ return 0;
+ }
+
+ tprints("{fm_flags=");
+ printflags64(fiemap_flags, args.fm_flags,
+ "FIEMAP_FLAG_???");
+ tprintf(", fm_mapped_extents=%u",
+ args.fm_mapped_extents);
+ tprints(", fm_extents=");
if (abbrev(tcp)) {
- tprints("...}");
+ tprints("...");
} else {
- tprints("[");
- info_addr = arg + offsetof(typeof(args), info);
- for (i = 0; i < args.dest_count; i++) {
- struct file_dedupe_range_info info;
- uint64_t addr = info_addr + sizeof(info) * i;
- if (i)
- tprints(", ");
-
- if (umoven(tcp, addr, sizeof(info), &info)) {
- tprints("...");
- break;
- }
-
- if (entering(tcp))
- tprintf("{dest_fd=%" PRIi64 ", "
- "dest_offset=%" PRIu64 "}",
- (int64_t)info.dest_fd,
- (uint64_t)info.dest_offset);
- else {
- tprintf("{bytes_deduped=%" PRIu64 ", "
- "status=%d}",
- (uint64_t)info.bytes_deduped,
- info.status);
- }
- }
- tprints("]}");
+ struct fiemap_extent fe;
+ print_array(tcp,
+ arg + offsetof(typeof(args), fm_extents),
+ args.fm_mapped_extents, &fe, sizeof(fe),
+ umoven_or_printaddr,
+ print_fiemap_extent, 0);
}
- if (entering(tcp))
- return 0;
+ tprints("}");
+
break;
}
+#endif /* HAVE_LINUX_FIEMAP_H */
default:
return RVAL_DECODED;