]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/reflink.c
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2015 Oracle, Inc.
14 static cmdinfo_t dedupe_cmd
;
15 static cmdinfo_t reflink_cmd
;
21 Links a range of bytes (in block size increments) from a file into a range\n\
22 of bytes in the open file. The contents of both file ranges must match.\n\
25 'dedupe some_file 0 4096 32768' - links 32768 bytes from some_file at\n\
26 offset 0 to into the open file at\n\
29 Reflink a range of blocks from a given input file to the open file. Both\n\
30 files share the same range of physical disk blocks; a write to the shared\n\
31 range of either file should result in the write landing in a new block and\n\
32 that range of the file being remapped (i.e. copy-on-write). Both files\n\
33 must reside on the same filesystem, and the contents of both ranges must\n\
46 struct xfs_extent_data
*args
;
47 struct xfs_extent_data_info
*info
;
51 args
= calloc(1, sizeof(struct xfs_extent_data
) +
52 sizeof(struct xfs_extent_data_info
));
55 info
= (struct xfs_extent_data_info
*)(args
+ 1);
56 args
->logical_offset
= soffset
;
60 info
->logical_offset
= doffset
;
62 while (args
->length
> 0 || !*ops
) {
63 error
= ioctl(fd
, XFS_IOC_FILE_EXTENT_SAME
, args
);
65 perror("XFS_IOC_FILE_EXTENT_SAME");
68 if (info
->status
< 0) {
69 fprintf(stderr
, "XFS_IOC_FILE_EXTENT_SAME: %s\n",
70 _(strerror(-info
->status
)));
73 if (info
->status
== XFS_EXTENT_DATA_DIFFERS
) {
74 fprintf(stderr
, "XFS_IOC_FILE_EXTENT_SAME: %s\n",
75 _("Extents did not match."));
78 if (args
->length
!= 0 &&
79 (info
->bytes_deduped
== 0 ||
80 info
->bytes_deduped
> args
->length
))
84 args
->logical_offset
+= info
->bytes_deduped
;
85 info
->logical_offset
+= info
->bytes_deduped
;
86 if (args
->length
>= info
->bytes_deduped
)
87 args
->length
-= info
->bytes_deduped
;
88 deduped
+= info
->bytes_deduped
;
100 off64_t soffset
, doffset
;
101 long long count
, total
;
103 int condensed
, quiet_flag
;
104 size_t fsblocksize
, fssectsize
;
105 struct timeval t1
, t2
;
106 int c
, ops
= 0, fd
= -1;
108 condensed
= quiet_flag
= 0;
109 init_cvtnum(&fsblocksize
, &fssectsize
);
111 while ((c
= getopt(argc
, argv
, "Cq")) != EOF
) {
120 return command_usage(&dedupe_cmd
);
123 if (optind
!= argc
- 4)
124 return command_usage(&dedupe_cmd
);
125 infile
= argv
[optind
];
127 soffset
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
129 printf(_("non-numeric src offset argument -- %s\n"), argv
[optind
]);
133 doffset
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
135 printf(_("non-numeric dest offset argument -- %s\n"), argv
[optind
]);
139 count
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
141 printf(_("non-positive length argument -- %s\n"), argv
[optind
]);
145 fd
= openfile(infile
, NULL
, IO_READONLY
, 0, NULL
);
149 gettimeofday(&t1
, NULL
);
150 total
= dedupe_ioctl(fd
, soffset
, doffset
, count
, &ops
);
151 if (ops
== 0 || quiet_flag
)
153 gettimeofday(&t2
, NULL
);
156 report_io_times("deduped", &t2
, (long long)doffset
, count
, total
, ops
,
167 Links a range of bytes (in block size increments) from a file into a range\n\
168 of bytes in the open file. The two extent ranges need not contain identical\n\
172 'reflink some_file 0 4096 32768' - links 32768 bytes from some_file at\n\
173 offset 0 to into the open file at\n\
175 'reflink some_file' - links all bytes from some_file into the open file\n\
178 Reflink a range of blocks from a given input file to the open file. Both\n\
179 files share the same range of physical disk blocks; a write to the shared\n\
180 range of either file should result in the write landing in a new block and\n\
181 that range of the file being remapped (i.e. copy-on-write). Both files\n\
182 must reside on the same filesystem.\n\
194 struct xfs_clone_args args
;
197 if (soffset
== 0 && doffset
== 0 && len
== 0) {
198 error
= ioctl(file
->fd
, XFS_IOC_CLONE
, fd
);
200 perror("XFS_IOC_CLONE");
203 args
.src_offset
= soffset
;
204 args
.src_length
= len
;
205 args
.dest_offset
= doffset
;
206 error
= ioctl(file
->fd
, XFS_IOC_CLONE_RANGE
, &args
);
208 perror("XFS_IOC_CLONE_RANGE");
212 return error
? 0 : len
;
220 off64_t soffset
, doffset
;
221 long long count
= 0, total
;
223 int condensed
, quiet_flag
;
224 size_t fsblocksize
, fssectsize
;
225 struct timeval t1
, t2
;
226 int c
, ops
= 0, fd
= -1;
228 condensed
= quiet_flag
= 0;
229 doffset
= soffset
= 0;
230 init_cvtnum(&fsblocksize
, &fssectsize
);
232 while ((c
= getopt(argc
, argv
, "Cq")) != EOF
) {
241 return command_usage(&reflink_cmd
);
244 if (optind
!= argc
- 4 && optind
!= argc
- 1)
245 return command_usage(&reflink_cmd
);
246 infile
= argv
[optind
];
250 soffset
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
252 printf(_("non-numeric src offset argument -- %s\n"), argv
[optind
]);
256 doffset
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
258 printf(_("non-numeric dest offset argument -- %s\n"), argv
[optind
]);
262 count
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
264 printf(_("non-positive length argument -- %s\n"), argv
[optind
]);
269 fd
= openfile(infile
, NULL
, IO_READONLY
, 0, NULL
);
273 gettimeofday(&t1
, NULL
);
274 total
= reflink_ioctl(fd
, soffset
, doffset
, count
, &ops
);
275 if (ops
== 0 || quiet_flag
)
277 gettimeofday(&t2
, NULL
);
280 report_io_times("linked", &t2
, (long long)doffset
, count
, total
, ops
,
290 reflink_cmd
.name
= "reflink";
291 reflink_cmd
.altname
= "rl";
292 reflink_cmd
.cfunc
= reflink_f
;
293 reflink_cmd
.argmin
= 1;
294 reflink_cmd
.argmax
= -1;
295 reflink_cmd
.flags
= CMD_NOMAP_OK
| CMD_FOREIGN_OK
| CMD_FLAG_ONESHOT
;
297 _("infile [src_off dst_off len]");
298 reflink_cmd
.oneline
=
299 _("reflinks an entire file, or a number of bytes at a specified offset");
300 reflink_cmd
.help
= reflink_help
;
302 add_command(&reflink_cmd
);
304 dedupe_cmd
.name
= "dedupe";
305 dedupe_cmd
.altname
= "dd";
306 dedupe_cmd
.cfunc
= dedupe_f
;
307 dedupe_cmd
.argmin
= 4;
308 dedupe_cmd
.argmax
= -1;
309 dedupe_cmd
.flags
= CMD_NOMAP_OK
| CMD_FOREIGN_OK
| CMD_FLAG_ONESHOT
;
311 _("infile src_off dst_off len");
313 _("dedupes a number of bytes at a specified offset");
314 dedupe_cmd
.help
= dedupe_help
;
316 add_command(&dedupe_cmd
);