]>
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");
69 if (info
->status
< 0) {
70 fprintf(stderr
, "XFS_IOC_FILE_EXTENT_SAME: %s\n",
71 _(strerror(-info
->status
)));
74 if (info
->status
== XFS_EXTENT_DATA_DIFFERS
) {
75 fprintf(stderr
, "XFS_IOC_FILE_EXTENT_SAME: %s\n",
76 _("Extents did not match."));
79 if (args
->length
!= 0 &&
80 (info
->bytes_deduped
== 0 ||
81 info
->bytes_deduped
> args
->length
))
85 args
->logical_offset
+= info
->bytes_deduped
;
86 info
->logical_offset
+= info
->bytes_deduped
;
87 if (args
->length
>= info
->bytes_deduped
)
88 args
->length
-= info
->bytes_deduped
;
89 deduped
+= info
->bytes_deduped
;
101 off_t soffset
, doffset
;
102 long long count
, total
;
104 int condensed
, quiet_flag
;
105 size_t fsblocksize
, fssectsize
;
106 struct timeval t1
, t2
;
107 int c
, ops
= 0, fd
= -1;
109 condensed
= quiet_flag
= 0;
110 init_cvtnum(&fsblocksize
, &fssectsize
);
112 while ((c
= getopt(argc
, argv
, "Cq")) != EOF
) {
122 return command_usage(&dedupe_cmd
);
125 if (optind
!= argc
- 4) {
127 return command_usage(&dedupe_cmd
);
129 infile
= argv
[optind
];
131 soffset
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
133 printf(_("non-numeric src offset argument -- %s\n"), argv
[optind
]);
138 doffset
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
140 printf(_("non-numeric dest offset argument -- %s\n"), argv
[optind
]);
145 count
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
147 printf(_("non-positive length argument -- %s\n"), argv
[optind
]);
152 fd
= openfile(infile
, NULL
, IO_READONLY
, 0, NULL
);
158 gettimeofday(&t1
, NULL
);
159 total
= dedupe_ioctl(fd
, soffset
, doffset
, count
, &ops
);
160 if (ops
== 0 || quiet_flag
)
162 gettimeofday(&t2
, NULL
);
165 report_io_times("deduped", &t2
, (long long)doffset
, count
, total
, ops
,
176 Links a range of bytes (in block size increments) from a file into a range\n\
177 of bytes in the open file. The two extent ranges need not contain identical\n\
181 'reflink some_file 0 4096 32768' - links 32768 bytes from some_file at\n\
182 offset 0 to into the open file at\n\
184 'reflink some_file' - links all bytes from some_file into the open file\n\
187 Reflink a range of blocks from a given input file to the open file. Both\n\
188 files share the same range of physical disk blocks; a write to the shared\n\
189 range of either file should result in the write landing in a new block and\n\
190 that range of the file being remapped (i.e. copy-on-write). Both files\n\
191 must reside on the same filesystem.\n\
203 struct xfs_clone_args args
;
206 if (soffset
== 0 && doffset
== 0 && len
== 0) {
207 error
= ioctl(file
->fd
, XFS_IOC_CLONE
, fd
);
209 perror("XFS_IOC_CLONE");
212 args
.src_offset
= soffset
;
213 args
.src_length
= len
;
214 args
.dest_offset
= doffset
;
215 error
= ioctl(file
->fd
, XFS_IOC_CLONE_RANGE
, &args
);
217 perror("XFS_IOC_CLONE_RANGE");
221 return error
? 0 : len
;
229 off_t soffset
, doffset
;
230 long long count
= 0, total
;
232 int condensed
, quiet_flag
;
233 size_t fsblocksize
, fssectsize
;
234 struct timeval t1
, t2
;
235 int c
, ops
= 0, fd
= -1;
237 condensed
= quiet_flag
= 0;
238 doffset
= soffset
= 0;
239 init_cvtnum(&fsblocksize
, &fssectsize
);
241 while ((c
= getopt(argc
, argv
, "Cq")) != EOF
) {
251 return command_usage(&reflink_cmd
);
254 if (optind
!= argc
- 4 && optind
!= argc
- 1) {
256 return command_usage(&reflink_cmd
);
258 infile
= argv
[optind
];
262 soffset
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
264 printf(_("non-numeric src offset argument -- %s\n"), argv
[optind
]);
269 doffset
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
271 printf(_("non-numeric dest offset argument -- %s\n"), argv
[optind
]);
276 count
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
278 printf(_("non-positive length argument -- %s\n"), argv
[optind
]);
284 fd
= openfile(infile
, NULL
, IO_READONLY
, 0, NULL
);
290 gettimeofday(&t1
, NULL
);
291 total
= reflink_ioctl(fd
, soffset
, doffset
, count
, &ops
);
297 gettimeofday(&t2
, NULL
);
300 report_io_times("linked", &t2
, (long long)doffset
, count
, total
, ops
,
310 reflink_cmd
.name
= "reflink";
311 reflink_cmd
.altname
= "rl";
312 reflink_cmd
.cfunc
= reflink_f
;
313 reflink_cmd
.argmin
= 1;
314 reflink_cmd
.argmax
= -1;
315 reflink_cmd
.flags
= CMD_NOMAP_OK
| CMD_FOREIGN_OK
| CMD_FLAG_ONESHOT
;
317 _("infile [src_off dst_off len]");
318 reflink_cmd
.oneline
=
319 _("reflinks an entire file, or a number of bytes at a specified offset");
320 reflink_cmd
.help
= reflink_help
;
322 add_command(&reflink_cmd
);
324 dedupe_cmd
.name
= "dedupe";
325 dedupe_cmd
.altname
= "dd";
326 dedupe_cmd
.cfunc
= dedupe_f
;
327 dedupe_cmd
.argmin
= 4;
328 dedupe_cmd
.argmax
= -1;
329 dedupe_cmd
.flags
= CMD_NOMAP_OK
| CMD_FOREIGN_OK
| CMD_FLAG_ONESHOT
;
331 _("infile src_off dst_off len");
333 _("dedupes a number of bytes at a specified offset");
334 dedupe_cmd
.help
= dedupe_help
;
336 add_command(&dedupe_cmd
);