2 * Module to make use of awesome Btrfs features
4 * Copyright (C) David Disseldorp 2011-2013
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "system/filesys.h"
22 #include <linux/ioctl.h>
24 #include <sys/ioctl.h>
29 #include "smbd/smbd.h"
30 #include "smbd/globals.h"
31 #include "librpc/gen_ndr/smbXsrv.h"
32 #include "librpc/gen_ndr/ioctl.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "offload_token.h"
36 static uint32_t btrfs_fs_capabilities(struct vfs_handle_struct
*handle
,
37 enum timestamp_set_resolution
*_ts_res
)
39 uint32_t fs_capabilities
;
40 enum timestamp_set_resolution ts_res
;
42 /* inherit default capabilities, expose compression support */
43 fs_capabilities
= SMB_VFS_NEXT_FS_CAPABILITIES(handle
, &ts_res
);
44 fs_capabilities
|= (FILE_FILE_COMPRESSION
45 | FILE_SUPPORTS_BLOCK_REFCOUNTING
);
48 return fs_capabilities
;
51 #define SHADOW_COPY_PREFIX "@GMT-" /* vfs_shadow_copy format */
52 #define SHADOW_COPY_PATH_FORMAT "@GMT-%Y.%m.%d-%H.%M.%S"
54 #define BTRFS_SUBVOL_RDONLY (1ULL << 1)
55 #define BTRFS_SUBVOL_NAME_MAX 4039
56 #define BTRFS_PATH_NAME_MAX 4087
57 struct btrfs_ioctl_vol_args_v2
{
62 char name
[BTRFS_SUBVOL_NAME_MAX
+ 1];
64 struct btrfs_ioctl_vol_args
{
66 char name
[BTRFS_PATH_NAME_MAX
+ 1];
69 struct btrfs_ioctl_clone_range_args
{
76 #define BTRFS_IOCTL_MAGIC 0x94
77 #define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \
78 struct btrfs_ioctl_clone_range_args)
79 #define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
80 struct btrfs_ioctl_vol_args)
81 #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
82 struct btrfs_ioctl_vol_args_v2)
84 static struct vfs_offload_ctx
*btrfs_offload_ctx
;
86 struct btrfs_offload_read_state
{
87 struct vfs_handle_struct
*handle
;
94 static void btrfs_offload_read_done(struct tevent_req
*subreq
);
96 static struct tevent_req
*btrfs_offload_read_send(
98 struct tevent_context
*ev
,
99 struct vfs_handle_struct
*handle
,
106 struct tevent_req
*req
= NULL
;
107 struct tevent_req
*subreq
= NULL
;
108 struct btrfs_offload_read_state
*state
= NULL
;
111 req
= tevent_req_create(mem_ctx
, &state
,
112 struct btrfs_offload_read_state
);
116 *state
= (struct btrfs_offload_read_state
) {
121 status
= vfs_offload_token_ctx_init(fsp
->conn
->sconn
->client
,
123 if (tevent_req_nterror(req
, status
)) {
124 return tevent_req_post(req
, ev
);
127 if (fsctl
== FSCTL_DUP_EXTENTS_TO_FILE
) {
128 status
= vfs_offload_token_create_blob(state
, fsp
, fsctl
,
130 if (tevent_req_nterror(req
, status
)) {
131 return tevent_req_post(req
, ev
);
134 status
= vfs_offload_token_db_store_fsp(btrfs_offload_ctx
, fsp
,
136 if (tevent_req_nterror(req
, status
)) {
137 return tevent_req_post(req
, ev
);
139 tevent_req_done(req
);
140 return tevent_req_post(req
, ev
);
143 subreq
= SMB_VFS_NEXT_OFFLOAD_READ_SEND(mem_ctx
, ev
, handle
, fsp
,
144 fsctl
, ttl
, offset
, to_copy
);
145 if (tevent_req_nomem(subreq
, req
)) {
146 return tevent_req_post(req
, ev
);
148 tevent_req_set_callback(subreq
, btrfs_offload_read_done
, req
);
152 static void btrfs_offload_read_done(struct tevent_req
*subreq
)
154 struct tevent_req
*req
= tevent_req_callback_data(
155 subreq
, struct tevent_req
);
156 struct btrfs_offload_read_state
*state
= tevent_req_data(
157 req
, struct btrfs_offload_read_state
);
160 status
= SMB_VFS_NEXT_OFFLOAD_READ_RECV(subreq
,
167 if (tevent_req_nterror(req
, status
)) {
171 status
= vfs_offload_token_db_store_fsp(btrfs_offload_ctx
,
174 if (tevent_req_nterror(req
, status
)) {
178 tevent_req_done(req
);
182 static NTSTATUS
btrfs_offload_read_recv(struct tevent_req
*req
,
183 struct vfs_handle_struct
*handle
,
189 struct btrfs_offload_read_state
*state
= tevent_req_data(
190 req
, struct btrfs_offload_read_state
);
193 if (tevent_req_is_nterror(req
, &status
)) {
194 tevent_req_received(req
);
198 *flags
= state
->flags
;
199 *xferlen
= state
->xferlen
;
200 token
->length
= state
->token
.length
;
201 token
->data
= talloc_move(mem_ctx
, &state
->token
.data
);
203 tevent_req_received(req
);
207 struct btrfs_offload_write_state
{
208 struct vfs_handle_struct
*handle
;
210 bool need_unbecome_user
;
213 static void btrfs_offload_write_cleanup(struct tevent_req
*req
,
214 enum tevent_req_state req_state
)
216 struct btrfs_offload_write_state
*state
=
218 struct btrfs_offload_write_state
);
221 if (!state
->need_unbecome_user
) {
225 ok
= unbecome_user_without_service();
227 state
->need_unbecome_user
= false;
230 static void btrfs_offload_write_done(struct tevent_req
*subreq
);
232 static struct tevent_req
*btrfs_offload_write_send(struct vfs_handle_struct
*handle
,
234 struct tevent_context
*ev
,
237 off_t transfer_offset
,
238 struct files_struct
*dest_fsp
,
242 struct tevent_req
*req
= NULL
;
243 struct btrfs_offload_write_state
*state
= NULL
;
244 struct tevent_req
*subreq
= NULL
;
245 struct btrfs_ioctl_clone_range_args cr_args
;
246 struct lock_struct src_lck
;
247 struct lock_struct dest_lck
;
248 off_t src_off
= transfer_offset
;
249 files_struct
*src_fsp
= NULL
;
251 bool handle_offload_write
= true;
252 bool do_locking
= false;
256 req
= tevent_req_create(mem_ctx
, &state
,
257 struct btrfs_offload_write_state
);
262 state
->handle
= handle
;
264 tevent_req_set_cleanup_fn(req
, btrfs_offload_write_cleanup
);
266 status
= vfs_offload_token_db_fetch_fsp(btrfs_offload_ctx
,
268 if (tevent_req_nterror(req
, status
)) {
269 return tevent_req_post(req
, ev
);
273 case FSCTL_SRV_COPYCHUNK
:
274 case FSCTL_SRV_COPYCHUNK_WRITE
:
278 case FSCTL_DUP_EXTENTS_TO_FILE
:
279 /* dup extents does not use locking */
283 handle_offload_write
= false;
289 * With a @src_length of zero, BTRFS_IOC_CLONE_RANGE clones
290 * all data from @src_offset->EOF! This is certainly not what
291 * the caller expects, and not what vfs_default does.
293 handle_offload_write
= false;
296 if (!handle_offload_write
) {
297 subreq
= SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle
,
306 if (tevent_req_nomem(subreq
, req
)) {
307 return tevent_req_post(req
, ev
);
309 tevent_req_set_callback(subreq
,
310 btrfs_offload_write_done
,
315 status
= vfs_offload_token_check_handles(
316 fsctl
, src_fsp
, dest_fsp
);
317 if (!NT_STATUS_IS_OK(status
)) {
318 tevent_req_nterror(req
, status
);
319 return tevent_req_post(req
, ev
);
322 ok
= become_user_without_service_by_fsp(src_fsp
);
324 tevent_req_nterror(req
, NT_STATUS_ACCESS_DENIED
);
325 return tevent_req_post(req
, ev
);
327 state
->need_unbecome_user
= true;
329 status
= vfs_stat_fsp(src_fsp
);
330 if (tevent_req_nterror(req
, status
)) {
331 return tevent_req_post(req
, ev
);
334 if (src_fsp
->fsp_name
->st
.st_ex_size
< src_off
+ num
) {
335 /* [MS-SMB2] Handling a Server-Side Data Copy Request */
336 tevent_req_nterror(req
, NT_STATUS_INVALID_VIEW_SIZE
);
337 return tevent_req_post(req
, ev
);
341 init_strict_lock_struct(src_fsp
,
342 src_fsp
->op
->global
->open_persistent_id
,
346 lp_posix_cifsu_locktype(src_fsp
),
348 if (!SMB_VFS_STRICT_LOCK_CHECK(src_fsp
->conn
, src_fsp
, &src_lck
)) {
349 tevent_req_nterror(req
, NT_STATUS_FILE_LOCK_CONFLICT
);
350 return tevent_req_post(req
, ev
);
354 ok
= unbecome_user_without_service();
356 state
->need_unbecome_user
= false;
359 init_strict_lock_struct(dest_fsp
,
360 dest_fsp
->op
->global
->open_persistent_id
,
364 lp_posix_cifsu_locktype(dest_fsp
),
367 if (!SMB_VFS_STRICT_LOCK_CHECK(dest_fsp
->conn
, dest_fsp
, &dest_lck
)) {
368 tevent_req_nterror(req
, NT_STATUS_FILE_LOCK_CONFLICT
);
369 return tevent_req_post(req
, ev
);
373 ZERO_STRUCT(cr_args
);
374 cr_args
.src_fd
= fsp_get_io_fd(src_fsp
);
375 cr_args
.src_offset
= (uint64_t)src_off
;
376 cr_args
.dest_offset
= (uint64_t)dest_off
;
377 cr_args
.src_length
= (uint64_t)num
;
379 ret
= ioctl(fsp_get_io_fd(dest_fsp
), BTRFS_IOC_CLONE_RANGE
, &cr_args
);
382 * BTRFS_IOC_CLONE_RANGE only supports 'sectorsize' aligned
383 * cloning. Which is 4096 by default, therefore fall back to
384 * manual read/write on failure.
386 DEBUG(5, ("BTRFS_IOC_CLONE_RANGE failed: %s, length %llu, "
387 "src fd: %lld off: %llu, dest fd: %d off: %llu\n",
389 (unsigned long long)cr_args
.src_length
,
390 (long long)cr_args
.src_fd
,
391 (unsigned long long)cr_args
.src_offset
,
392 fsp_get_io_fd(dest_fsp
),
393 (unsigned long long)cr_args
.dest_offset
));
394 subreq
= SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle
,
403 if (tevent_req_nomem(subreq
, req
)) {
404 return tevent_req_post(req
, ev
);
406 /* wait for subreq completion */
407 tevent_req_set_callback(subreq
,
408 btrfs_offload_write_done
,
413 DEBUG(5, ("BTRFS_IOC_CLONE_RANGE returned %d\n", ret
));
414 /* BTRFS_IOC_CLONE_RANGE is all or nothing */
416 tevent_req_done(req
);
417 return tevent_req_post(req
, ev
);
420 /* only used if the request is passed through to next VFS module */
421 static void btrfs_offload_write_done(struct tevent_req
*subreq
)
423 struct tevent_req
*req
=
424 tevent_req_callback_data(subreq
,
426 struct btrfs_offload_write_state
*state
=
428 struct btrfs_offload_write_state
);
431 status
= SMB_VFS_NEXT_OFFLOAD_WRITE_RECV(state
->handle
,
435 if (tevent_req_nterror(req
, status
)) {
438 tevent_req_done(req
);
441 static NTSTATUS
btrfs_offload_write_recv(struct vfs_handle_struct
*handle
,
442 struct tevent_req
*req
,
445 struct btrfs_offload_write_state
*state
=
447 struct btrfs_offload_write_state
);
450 if (tevent_req_is_nterror(req
, &status
)) {
451 DEBUG(4, ("server side copy chunk failed: %s\n",
453 tevent_req_received(req
);
457 DEBUG(10, ("server side copy chunk copied %llu\n",
458 (unsigned long long)state
->copied
));
459 *copied
= state
->copied
;
460 tevent_req_received(req
);
464 static NTSTATUS
btrfs_fget_compression(struct vfs_handle_struct
*handle
,
466 struct files_struct
*fsp
,
467 uint16_t *_compression_fmt
)
470 const char *p
= NULL
;
473 int fsp_fd
= fsp_get_pathref_fd(fsp
);
477 if (!fsp
->fsp_flags
.is_pathref
) {
478 ret
= ioctl(fsp_fd
, FS_IOC_GETFLAGS
, &flags
);
480 DBG_WARNING("FS_IOC_GETFLAGS failed: %s, fd %lld\n",
481 strerror(errno
), (long long)fd
);
482 return map_nt_error_from_unix(errno
);
484 if (flags
& FS_COMPR_FL
) {
485 *_compression_fmt
= COMPRESSION_FORMAT_LZNT1
;
487 *_compression_fmt
= COMPRESSION_FORMAT_NONE
;
492 if (!fsp
->fsp_flags
.have_proc_fds
) {
493 return NT_STATUS_NOT_IMPLEMENTED
;
496 p
= sys_proc_fd_path(fsp_fd
, buf
, sizeof(buf
));
498 return NT_STATUS_NO_MEMORY
;
501 fd
= open(p
, O_RDONLY
);
503 DBG_DEBUG("/proc open of %s failed: %s\n", p
, strerror(errno
));
504 return map_nt_error_from_unix(errno
);
507 ret
= ioctl(fd
, FS_IOC_GETFLAGS
, &flags
);
509 DEBUG(1, ("FS_IOC_GETFLAGS failed: %s, fd %lld\n",
510 strerror(errno
), (long long)fd
));
511 status
= map_nt_error_from_unix(errno
);
514 if (flags
& FS_COMPR_FL
) {
515 *_compression_fmt
= COMPRESSION_FORMAT_LZNT1
;
517 *_compression_fmt
= COMPRESSION_FORMAT_NONE
;
519 status
= NT_STATUS_OK
;
529 static NTSTATUS
btrfs_set_compression(struct vfs_handle_struct
*handle
,
531 struct files_struct
*fsp
,
532 uint16_t compression_fmt
)
539 if ((fsp
== NULL
) || (fsp_get_io_fd(fsp
) == -1)) {
540 status
= NT_STATUS_INVALID_PARAMETER
;
543 fd
= fsp_get_io_fd(fsp
);
545 ret
= ioctl(fd
, FS_IOC_GETFLAGS
, &flags
);
547 DEBUG(1, ("FS_IOC_GETFLAGS failed: %s, fd %d\n",
548 strerror(errno
), fd
));
549 status
= map_nt_error_from_unix(errno
);
553 if (compression_fmt
== COMPRESSION_FORMAT_NONE
) {
554 DEBUG(5, ("setting compression\n"));
555 flags
&= (~FS_COMPR_FL
);
556 } else if ((compression_fmt
== COMPRESSION_FORMAT_DEFAULT
)
557 || (compression_fmt
== COMPRESSION_FORMAT_LZNT1
)) {
558 DEBUG(5, ("clearing compression\n"));
559 flags
|= FS_COMPR_FL
;
561 DEBUG(1, ("invalid compression format 0x%x\n",
562 (int)compression_fmt
));
563 status
= NT_STATUS_INVALID_PARAMETER
;
567 ret
= ioctl(fd
, FS_IOC_SETFLAGS
, &flags
);
569 DEBUG(1, ("FS_IOC_SETFLAGS failed: %s, fd %d\n",
570 strerror(errno
), fd
));
571 status
= map_nt_error_from_unix(errno
);
574 status
= NT_STATUS_OK
;
580 * Check whether a path can be shadow copied. Return the base volume, allowing
581 * the caller to determine if multiple paths lie on the same base volume.
583 #define BTRFS_INODE_SUBVOL 256
584 static NTSTATUS
btrfs_snap_check_path(struct vfs_handle_struct
*handle
,
586 const char *service_path
,
592 if (!lp_parm_bool(SNUM(handle
->conn
),
593 "btrfs", "manipulate snapshots", false)) {
594 DEBUG(2, ("Btrfs snapshot manipulation disabled, passing\n"));
595 return SMB_VFS_NEXT_SNAP_CHECK_PATH(handle
, mem_ctx
,
596 service_path
, base_volume
);
599 /* btrfs userspace uses this logic to confirm subvolume */
600 if (stat(service_path
, &st
) < 0) {
601 return NT_STATUS_NOT_SUPPORTED
;
603 if ((st
.st_ino
!= BTRFS_INODE_SUBVOL
) || !S_ISDIR(st
.st_mode
)) {
604 DEBUG(0, ("%s not a btrfs subvolume, snapshots not available\n",
606 return NT_STATUS_NOT_SUPPORTED
;
609 /* we "snapshot" the service path itself */
610 base
= talloc_strdup(mem_ctx
, service_path
);
612 return NT_STATUS_NO_MEMORY
;
619 static NTSTATUS
btrfs_gen_snap_dest_path(TALLOC_CTX
*mem_ctx
,
620 const char *src_path
,
622 char **dest_path
, char **subvolume
)
628 gmtime_r(tstamp
, &t_gmt
);
630 tlen
= strftime(time_str
, ARRAY_SIZE(time_str
),
631 SHADOW_COPY_PATH_FORMAT
, &t_gmt
);
633 return NT_STATUS_UNSUCCESSFUL
;
636 *dest_path
= talloc_strdup(mem_ctx
, src_path
);
637 *subvolume
= talloc_strdup(mem_ctx
, time_str
);
638 if ((*dest_path
== NULL
) || (*subvolume
== NULL
)) {
639 return NT_STATUS_NO_MEMORY
;
645 static NTSTATUS
btrfs_snap_create(struct vfs_handle_struct
*handle
,
647 const char *base_volume
,
653 struct btrfs_ioctl_vol_args_v2 ioctl_arg
;
658 char *dest_path
= NULL
;
659 char *dest_subvolume
= NULL
;
668 if (!lp_parm_bool(SNUM(handle
->conn
),
669 "btrfs", "manipulate snapshots", false)) {
670 DEBUG(2, ("Btrfs snapshot manipulation disabled, passing\n"));
671 return SMB_VFS_NEXT_SNAP_CREATE(handle
, mem_ctx
, base_volume
,
672 tstamp
, rw
, _base_path
,
676 tmp_ctx
= talloc_new(mem_ctx
);
677 if (tmp_ctx
== NULL
) {
678 return NT_STATUS_NO_MEMORY
;
681 base_path
= talloc_strdup(tmp_ctx
, base_volume
);
682 if (base_path
== NULL
) {
683 talloc_free(tmp_ctx
);
684 return NT_STATUS_NO_MEMORY
;
687 status
= btrfs_gen_snap_dest_path(tmp_ctx
, base_volume
, tstamp
,
688 &dest_path
, &dest_subvolume
);
689 if (!NT_STATUS_IS_OK(status
)) {
690 talloc_free(tmp_ctx
);
694 snap_path
= talloc_asprintf(tmp_ctx
, "%s/%s", dest_path
,
696 if (snap_path
== NULL
) {
697 talloc_free(tmp_ctx
);
698 return NT_STATUS_NO_MEMORY
;
701 src_dir
= opendir(base_volume
);
702 if (src_dir
== NULL
) {
703 DEBUG(0, ("snap src %s open failed: %s\n",
704 base_volume
, strerror(errno
)));
705 status
= map_nt_error_from_unix(errno
);
706 talloc_free(tmp_ctx
);
709 src_fd
= dirfd(src_dir
);
711 status
= map_nt_error_from_unix(errno
);
713 talloc_free(tmp_ctx
);
717 dest_dir
= opendir(dest_path
);
718 if (dest_dir
== NULL
) {
719 DEBUG(0, ("snap dest %s open failed: %s\n",
720 dest_path
, strerror(errno
)));
721 status
= map_nt_error_from_unix(errno
);
723 talloc_free(tmp_ctx
);
726 dest_fd
= dirfd(dest_dir
);
728 status
= map_nt_error_from_unix(errno
);
731 talloc_free(tmp_ctx
);
735 /* avoid zeroing the entire struct here, name is 4k */
736 ioctl_arg
.fd
= src_fd
;
737 ioctl_arg
.transid
= 0;
738 ioctl_arg
.flags
= (rw
== false) ? BTRFS_SUBVOL_RDONLY
: 0;
739 memset(ioctl_arg
.unused
, 0, sizeof(ioctl_arg
.unused
));
740 len
= strlcpy(ioctl_arg
.name
, dest_subvolume
,
741 ARRAY_SIZE(ioctl_arg
.name
));
742 if (len
>= ARRAY_SIZE(ioctl_arg
.name
)) {
743 DEBUG(1, ("subvolume name too long for SNAP_CREATE ioctl\n"));
746 talloc_free(tmp_ctx
);
747 return NT_STATUS_INVALID_PARAMETER
;
751 ret
= ioctl(dest_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &ioctl_arg
);
755 DEBUG(0, ("%s -> %s(%s) BTRFS_IOC_SNAP_CREATE_V2 failed: %s\n",
756 base_volume
, dest_path
, dest_subvolume
,
757 strerror(saved_errno
)));
758 status
= map_nt_error_from_unix(saved_errno
);
761 talloc_free(tmp_ctx
);
764 DEBUG(5, ("%s -> %s(%s) BTRFS_IOC_SNAP_CREATE_V2 done\n",
765 base_volume
, dest_path
, dest_subvolume
));
767 *_base_path
= talloc_steal(mem_ctx
, base_path
);
768 *_snap_path
= talloc_steal(mem_ctx
, snap_path
);
771 talloc_free(tmp_ctx
);
776 static NTSTATUS
btrfs_snap_delete(struct vfs_handle_struct
*handle
,
785 struct btrfs_ioctl_vol_args ioctl_arg
;
794 if (!lp_parm_bool(SNUM(handle
->conn
),
795 "btrfs", "manipulate snapshots", false)) {
796 DEBUG(2, ("Btrfs snapshot manipulation disabled, passing\n"));
797 return SMB_VFS_NEXT_SNAP_DELETE(handle
, mem_ctx
,
798 base_path
, snap_path
);
801 tmp_ctx
= talloc_new(mem_ctx
);
802 if (tmp_ctx
== NULL
) {
803 return NT_STATUS_NO_MEMORY
;
806 dest_path
= talloc_strdup(tmp_ctx
, snap_path
);
807 if (dest_path
== NULL
) {
808 talloc_free(tmp_ctx
);
809 return NT_STATUS_NO_MEMORY
;
811 subvolume
= talloc_strdup(tmp_ctx
, snap_path
);
812 if (subvolume
== NULL
) {
813 talloc_free(tmp_ctx
);
814 return NT_STATUS_NO_MEMORY
;
816 dest_path
= dirname(dest_path
);
817 subvolume
= basename(subvolume
);
819 /* confirm snap_path matches creation format */
820 tstr
= strptime(subvolume
, SHADOW_COPY_PATH_FORMAT
, &t_gmt
);
821 if ((tstr
== NULL
) || (*tstr
!= '\0')) {
822 DEBUG(0, ("snapshot path %s does not match creation format\n",
824 talloc_free(tmp_ctx
);
825 return NT_STATUS_UNSUCCESSFUL
;
828 dest_dir
= opendir(dest_path
);
829 if (dest_dir
== NULL
) {
830 DEBUG(0, ("snap destroy dest %s open failed: %s\n",
831 dest_path
, strerror(errno
)));
832 status
= map_nt_error_from_unix(errno
);
833 talloc_free(tmp_ctx
);
836 dest_fd
= dirfd(dest_dir
);
838 status
= map_nt_error_from_unix(errno
);
840 talloc_free(tmp_ctx
);
844 ioctl_arg
.fd
= -1; /* not needed */
845 len
= strlcpy(ioctl_arg
.name
, subvolume
, ARRAY_SIZE(ioctl_arg
.name
));
846 if (len
>= ARRAY_SIZE(ioctl_arg
.name
)) {
847 DEBUG(1, ("subvolume name too long for SNAP_DESTROY ioctl\n"));
849 talloc_free(tmp_ctx
);
850 return NT_STATUS_INVALID_PARAMETER
;
854 ret
= ioctl(dest_fd
, BTRFS_IOC_SNAP_DESTROY
, &ioctl_arg
);
858 DEBUG(0, ("%s(%s) BTRFS_IOC_SNAP_DESTROY failed: %s\n",
859 dest_path
, subvolume
, strerror(saved_errno
)));
860 status
= map_nt_error_from_unix(saved_errno
);
862 talloc_free(tmp_ctx
);
865 DEBUG(5, ("%s(%s) BTRFS_IOC_SNAP_DESTROY done\n",
866 dest_path
, subvolume
));
869 talloc_free(tmp_ctx
);
873 static struct vfs_fn_pointers btrfs_fns
= {
874 .fs_capabilities_fn
= btrfs_fs_capabilities
,
875 .offload_read_send_fn
= btrfs_offload_read_send
,
876 .offload_read_recv_fn
= btrfs_offload_read_recv
,
877 .offload_write_send_fn
= btrfs_offload_write_send
,
878 .offload_write_recv_fn
= btrfs_offload_write_recv
,
879 .fget_compression_fn
= btrfs_fget_compression
,
880 .set_compression_fn
= btrfs_set_compression
,
881 .snap_check_path_fn
= btrfs_snap_check_path
,
882 .snap_create_fn
= btrfs_snap_create
,
883 .snap_delete_fn
= btrfs_snap_delete
,
887 NTSTATUS
vfs_btrfs_init(TALLOC_CTX
*ctx
)
889 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION
,
890 "btrfs", &btrfs_fns
);