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/>.
20 #include <linux/ioctl.h>
22 #include <sys/ioctl.h>
27 #include "system/filesys.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;
92 static void btrfs_offload_read_done(struct tevent_req *subreq);
94 static struct tevent_req *btrfs_offload_read_send(
96 struct tevent_context *ev,
97 struct vfs_handle_struct *handle,
104 struct tevent_req *req = NULL;
105 struct tevent_req *subreq = NULL;
106 struct btrfs_offload_read_state *state = NULL;
109 req = tevent_req_create(mem_ctx, &state,
110 struct btrfs_offload_read_state);
114 *state = (struct btrfs_offload_read_state) {
119 status = vfs_offload_token_ctx_init(fsp->conn->sconn->client,
121 if (tevent_req_nterror(req, status)) {
122 return tevent_req_post(req, ev);
125 if (fsctl == FSCTL_DUP_EXTENTS_TO_FILE) {
126 status = vfs_offload_token_create_blob(state, fsp, fsctl,
128 if (tevent_req_nterror(req, status)) {
129 return tevent_req_post(req, ev);
132 status = vfs_offload_token_db_store_fsp(btrfs_offload_ctx, fsp,
134 if (tevent_req_nterror(req, status)) {
135 return tevent_req_post(req, ev);
137 tevent_req_done(req);
138 return tevent_req_post(req, ev);
141 subreq = SMB_VFS_NEXT_OFFLOAD_READ_SEND(mem_ctx, ev, handle, fsp,
142 fsctl, ttl, offset, to_copy);
143 if (tevent_req_nomem(subreq, req)) {
144 return tevent_req_post(req, ev);
146 tevent_req_set_callback(subreq, btrfs_offload_read_done, req);
150 static void btrfs_offload_read_done(struct tevent_req *subreq)
152 struct tevent_req *req = tevent_req_callback_data(
153 subreq, struct tevent_req);
154 struct btrfs_offload_read_state *state = tevent_req_data(
155 req, struct btrfs_offload_read_state);
158 status = SMB_VFS_NEXT_OFFLOAD_READ_RECV(subreq,
163 if (tevent_req_nterror(req, status)) {
167 status = vfs_offload_token_db_store_fsp(btrfs_offload_ctx,
170 if (tevent_req_nterror(req, status)) {
174 tevent_req_done(req);
178 static NTSTATUS btrfs_offload_read_recv(struct tevent_req *req,
179 struct vfs_handle_struct *handle,
183 struct btrfs_offload_read_state *state = tevent_req_data(
184 req, struct btrfs_offload_read_state);
187 if (tevent_req_is_nterror(req, &status)) {
188 tevent_req_received(req);
192 token->length = state->token.length;
193 token->data = talloc_move(mem_ctx, &state->token.data);
195 tevent_req_received(req);
199 struct btrfs_offload_write_state {
200 struct vfs_handle_struct *handle;
202 bool need_unbecome_user;
205 static void btrfs_offload_write_cleanup(struct tevent_req *req,
206 enum tevent_req_state req_state)
208 struct btrfs_offload_write_state *state =
210 struct btrfs_offload_write_state);
213 if (!state->need_unbecome_user) {
217 ok = unbecome_user_without_service();
219 state->need_unbecome_user = false;
222 static void btrfs_offload_write_done(struct tevent_req *subreq);
224 static struct tevent_req *btrfs_offload_write_send(struct vfs_handle_struct *handle,
226 struct tevent_context *ev,
229 off_t transfer_offset,
230 struct files_struct *dest_fsp,
234 struct tevent_req *req = NULL;
235 struct btrfs_offload_write_state *state = NULL;
236 struct tevent_req *subreq = NULL;
237 struct btrfs_ioctl_clone_range_args cr_args;
238 struct lock_struct src_lck;
239 struct lock_struct dest_lck;
240 off_t src_off = transfer_offset;
241 files_struct *src_fsp = NULL;
243 bool handle_offload_write = true;
244 bool do_locking = false;
248 req = tevent_req_create(mem_ctx, &state,
249 struct btrfs_offload_write_state);
254 state->handle = handle;
256 tevent_req_set_cleanup_fn(req, btrfs_offload_write_cleanup);
258 status = vfs_offload_token_db_fetch_fsp(btrfs_offload_ctx,
260 if (tevent_req_nterror(req, status)) {
261 return tevent_req_post(req, ev);
265 case FSCTL_SRV_COPYCHUNK:
266 case FSCTL_SRV_COPYCHUNK_WRITE:
270 case FSCTL_DUP_EXTENTS_TO_FILE:
271 /* dup extents does not use locking */
275 handle_offload_write = false;
281 * With a @src_length of zero, BTRFS_IOC_CLONE_RANGE clones
282 * all data from @src_offset->EOF! This is certainly not what
283 * the caller expects, and not what vfs_default does.
285 handle_offload_write = false;
288 if (!handle_offload_write) {
289 subreq = SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle,
298 if (tevent_req_nomem(subreq, req)) {
299 return tevent_req_post(req, ev);
301 tevent_req_set_callback(subreq,
302 btrfs_offload_write_done,
307 status = vfs_offload_token_check_handles(
308 fsctl, src_fsp, dest_fsp);
309 if (!NT_STATUS_IS_OK(status)) {
310 tevent_req_nterror(req, status);
311 return tevent_req_post(req, ev);
314 ok = become_user_without_service_by_fsp(src_fsp);
316 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
317 return tevent_req_post(req, ev);
319 state->need_unbecome_user = true;
321 status = vfs_stat_fsp(src_fsp);
322 if (tevent_req_nterror(req, status)) {
323 return tevent_req_post(req, ev);
326 if (src_fsp->fsp_name->st.st_ex_size < src_off + num) {
327 /* [MS-SMB2] Handling a Server-Side Data Copy Request */
328 tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE);
329 return tevent_req_post(req, ev);
333 init_strict_lock_struct(src_fsp,
334 src_fsp->op->global->open_persistent_id,
339 if (!SMB_VFS_STRICT_LOCK_CHECK(src_fsp->conn, src_fsp, &src_lck)) {
340 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
341 return tevent_req_post(req, ev);
345 ok = unbecome_user_without_service();
347 state->need_unbecome_user = false;
350 init_strict_lock_struct(dest_fsp,
351 dest_fsp->op->global->open_persistent_id,
357 if (!SMB_VFS_STRICT_LOCK_CHECK(dest_fsp->conn, dest_fsp, &dest_lck)) {
358 tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
359 return tevent_req_post(req, ev);
363 ZERO_STRUCT(cr_args);
364 cr_args.src_fd = fsp_get_io_fd(src_fsp);
365 cr_args.src_offset = (uint64_t)src_off;
366 cr_args.dest_offset = (uint64_t)dest_off;
367 cr_args.src_length = (uint64_t)num;
369 ret = ioctl(fsp_get_io_fd(dest_fsp), BTRFS_IOC_CLONE_RANGE, &cr_args);
372 * BTRFS_IOC_CLONE_RANGE only supports 'sectorsize' aligned
373 * cloning. Which is 4096 by default, therefore fall back to
374 * manual read/write on failure.
376 DEBUG(5, ("BTRFS_IOC_CLONE_RANGE failed: %s, length %llu, "
377 "src fd: %lld off: %llu, dest fd: %d off: %llu\n",
379 (unsigned long long)cr_args.src_length,
380 (long long)cr_args.src_fd,
381 (unsigned long long)cr_args.src_offset,
382 fsp_get_io_fd(dest_fsp),
383 (unsigned long long)cr_args.dest_offset));
384 subreq = SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle,
393 if (tevent_req_nomem(subreq, req)) {
394 return tevent_req_post(req, ev);
396 /* wait for subreq completion */
397 tevent_req_set_callback(subreq,
398 btrfs_offload_write_done,
403 DEBUG(5, ("BTRFS_IOC_CLONE_RANGE returned %d\n", ret));
404 /* BTRFS_IOC_CLONE_RANGE is all or nothing */
406 tevent_req_done(req);
407 return tevent_req_post(req, ev);
410 /* only used if the request is passed through to next VFS module */
411 static void btrfs_offload_write_done(struct tevent_req *subreq)
413 struct tevent_req *req =
414 tevent_req_callback_data(subreq,
416 struct btrfs_offload_write_state *state =
418 struct btrfs_offload_write_state);
421 status = SMB_VFS_NEXT_OFFLOAD_WRITE_RECV(state->handle,
425 if (tevent_req_nterror(req, status)) {
428 tevent_req_done(req);
431 static NTSTATUS btrfs_offload_write_recv(struct vfs_handle_struct *handle,
432 struct tevent_req *req,
435 struct btrfs_offload_write_state *state =
437 struct btrfs_offload_write_state);
440 if (tevent_req_is_nterror(req, &status)) {
441 DEBUG(4, ("server side copy chunk failed: %s\n",
443 tevent_req_received(req);
447 DEBUG(10, ("server side copy chunk copied %llu\n",
448 (unsigned long long)state->copied));
449 *copied = state->copied;
450 tevent_req_received(req);
454 static NTSTATUS btrfs_fget_compression(struct vfs_handle_struct *handle,
456 struct files_struct *fsp,
457 uint16_t *_compression_fmt)
460 const char *p = NULL;
466 if (!fsp->fsp_flags.is_pathref) {
467 ret = ioctl(fd, FS_IOC_GETFLAGS, &flags);
469 DBG_WARNING("FS_IOC_GETFLAGS failed: %s, fd %lld\n",
470 strerror(errno), (long long)fd);
471 return map_nt_error_from_unix(errno);
473 if (flags & FS_COMPR_FL) {
474 *_compression_fmt = COMPRESSION_FORMAT_LZNT1;
476 *_compression_fmt = COMPRESSION_FORMAT_NONE;
481 if (!fsp->fsp_flags.have_proc_fds) {
482 return NT_STATUS_NOT_IMPLEMENTED;
485 fd = fsp_get_pathref_fd(fsp);
487 p = sys_proc_fd_path(fd, buf, sizeof(buf));
489 return NT_STATUS_NO_MEMORY;
492 fd = open(p, O_RDONLY);
494 DBG_ERR("/proc open of %s failed: %s\n", p, strerror(errno));
495 return map_nt_error_from_unix(errno);
498 ret = ioctl(fd, FS_IOC_GETFLAGS, &flags);
500 DEBUG(1, ("FS_IOC_GETFLAGS failed: %s, fd %lld\n",
501 strerror(errno), (long long)fd));
502 status = map_nt_error_from_unix(errno);
505 if (flags & FS_COMPR_FL) {
506 *_compression_fmt = COMPRESSION_FORMAT_LZNT1;
508 *_compression_fmt = COMPRESSION_FORMAT_NONE;
510 status = NT_STATUS_OK;
520 static NTSTATUS btrfs_set_compression(struct vfs_handle_struct *handle,
522 struct files_struct *fsp,
523 uint16_t compression_fmt)
530 if ((fsp == NULL) || (fsp_get_io_fd(fsp) == -1)) {
531 status = NT_STATUS_INVALID_PARAMETER;
534 fd = fsp_get_io_fd(fsp);
536 ret = ioctl(fd, FS_IOC_GETFLAGS, &flags);
538 DEBUG(1, ("FS_IOC_GETFLAGS failed: %s, fd %d\n",
539 strerror(errno), fd));
540 status = map_nt_error_from_unix(errno);
544 if (compression_fmt == COMPRESSION_FORMAT_NONE) {
545 DEBUG(5, ("setting compression\n"));
546 flags &= (~FS_COMPR_FL);
547 } else if ((compression_fmt == COMPRESSION_FORMAT_DEFAULT)
548 || (compression_fmt == COMPRESSION_FORMAT_LZNT1)) {
549 DEBUG(5, ("clearing compression\n"));
550 flags |= FS_COMPR_FL;
552 DEBUG(1, ("invalid compression format 0x%x\n",
553 (int)compression_fmt));
554 status = NT_STATUS_INVALID_PARAMETER;
558 ret = ioctl(fd, FS_IOC_SETFLAGS, &flags);
560 DEBUG(1, ("FS_IOC_SETFLAGS failed: %s, fd %d\n",
561 strerror(errno), fd));
562 status = map_nt_error_from_unix(errno);
565 status = NT_STATUS_OK;
571 * Check whether a path can be shadow copied. Return the base volume, allowing
572 * the caller to determine if multiple paths lie on the same base volume.
574 #define BTRFS_INODE_SUBVOL 256
575 static NTSTATUS btrfs_snap_check_path(struct vfs_handle_struct *handle,
577 const char *service_path,
583 if (!lp_parm_bool(SNUM(handle->conn),
584 "btrfs", "manipulate snapshots", false)) {
585 DEBUG(2, ("Btrfs snapshot manipulation disabled, passing\n"));
586 return SMB_VFS_NEXT_SNAP_CHECK_PATH(handle, mem_ctx,
587 service_path, base_volume);
590 /* btrfs userspace uses this logic to confirm subvolume */
591 if (stat(service_path, &st) < 0) {
592 return NT_STATUS_NOT_SUPPORTED;
594 if ((st.st_ino != BTRFS_INODE_SUBVOL) || !S_ISDIR(st.st_mode)) {
595 DEBUG(0, ("%s not a btrfs subvolume, snapshots not available\n",
597 return NT_STATUS_NOT_SUPPORTED;
600 /* we "snapshot" the service path itself */
601 base = talloc_strdup(mem_ctx, service_path);
603 return NT_STATUS_NO_MEMORY;
610 static NTSTATUS btrfs_gen_snap_dest_path(TALLOC_CTX *mem_ctx,
611 const char *src_path,
613 char **dest_path, char **subvolume)
619 gmtime_r(tstamp, &t_gmt);
621 tlen = strftime(time_str, ARRAY_SIZE(time_str),
622 SHADOW_COPY_PATH_FORMAT, &t_gmt);
624 return NT_STATUS_UNSUCCESSFUL;
627 *dest_path = talloc_strdup(mem_ctx, src_path);
628 *subvolume = talloc_strdup(mem_ctx, time_str);
629 if ((*dest_path == NULL) || (*subvolume == NULL)) {
630 return NT_STATUS_NO_MEMORY;
636 static NTSTATUS btrfs_snap_create(struct vfs_handle_struct *handle,
638 const char *base_volume,
644 struct btrfs_ioctl_vol_args_v2 ioctl_arg;
649 char *dest_path = NULL;
650 char *dest_subvolume = NULL;
659 if (!lp_parm_bool(SNUM(handle->conn),
660 "btrfs", "manipulate snapshots", false)) {
661 DEBUG(2, ("Btrfs snapshot manipulation disabled, passing\n"));
662 return SMB_VFS_NEXT_SNAP_CREATE(handle, mem_ctx, base_volume,
663 tstamp, rw, _base_path,
667 tmp_ctx = talloc_new(mem_ctx);
668 if (tmp_ctx == NULL) {
669 return NT_STATUS_NO_MEMORY;
672 base_path = talloc_strdup(tmp_ctx, base_volume);
673 if (base_path == NULL) {
674 talloc_free(tmp_ctx);
675 return NT_STATUS_NO_MEMORY;
678 status = btrfs_gen_snap_dest_path(tmp_ctx, base_volume, tstamp,
679 &dest_path, &dest_subvolume);
680 if (!NT_STATUS_IS_OK(status)) {
681 talloc_free(tmp_ctx);
685 snap_path = talloc_asprintf(tmp_ctx, "%s/%s", dest_path,
687 if (snap_path == NULL) {
688 talloc_free(tmp_ctx);
689 return NT_STATUS_NO_MEMORY;
692 src_dir = opendir(base_volume);
693 if (src_dir == NULL) {
694 DEBUG(0, ("snap src %s open failed: %s\n",
695 base_volume, strerror(errno)));
696 status = map_nt_error_from_unix(errno);
697 talloc_free(tmp_ctx);
700 src_fd = dirfd(src_dir);
702 status = map_nt_error_from_unix(errno);
704 talloc_free(tmp_ctx);
708 dest_dir = opendir(dest_path);
709 if (dest_dir == NULL) {
710 DEBUG(0, ("snap dest %s open failed: %s\n",
711 dest_path, strerror(errno)));
712 status = map_nt_error_from_unix(errno);
714 talloc_free(tmp_ctx);
717 dest_fd = dirfd(dest_dir);
719 status = map_nt_error_from_unix(errno);
722 talloc_free(tmp_ctx);
726 /* avoid zeroing the entire struct here, name is 4k */
727 ioctl_arg.fd = src_fd;
728 ioctl_arg.transid = 0;
729 ioctl_arg.flags = (rw == false) ? BTRFS_SUBVOL_RDONLY : 0;
730 memset(ioctl_arg.unused, 0, sizeof(ioctl_arg.unused));
731 len = strlcpy(ioctl_arg.name, dest_subvolume,
732 ARRAY_SIZE(ioctl_arg.name));
733 if (len >= ARRAY_SIZE(ioctl_arg.name)) {
734 DEBUG(1, ("subvolume name too long for SNAP_CREATE ioctl\n"));
737 talloc_free(tmp_ctx);
738 return NT_STATUS_INVALID_PARAMETER;
742 ret = ioctl(dest_fd, BTRFS_IOC_SNAP_CREATE_V2, &ioctl_arg);
746 DEBUG(0, ("%s -> %s(%s) BTRFS_IOC_SNAP_CREATE_V2 failed: %s\n",
747 base_volume, dest_path, dest_subvolume,
748 strerror(saved_errno)));
749 status = map_nt_error_from_unix(saved_errno);
752 talloc_free(tmp_ctx);
755 DEBUG(5, ("%s -> %s(%s) BTRFS_IOC_SNAP_CREATE_V2 done\n",
756 base_volume, dest_path, dest_subvolume));
758 *_base_path = talloc_steal(mem_ctx, base_path);
759 *_snap_path = talloc_steal(mem_ctx, snap_path);
762 talloc_free(tmp_ctx);
767 static NTSTATUS btrfs_snap_delete(struct vfs_handle_struct *handle,
776 struct btrfs_ioctl_vol_args ioctl_arg;
785 if (!lp_parm_bool(SNUM(handle->conn),
786 "btrfs", "manipulate snapshots", false)) {
787 DEBUG(2, ("Btrfs snapshot manipulation disabled, passing\n"));
788 return SMB_VFS_NEXT_SNAP_DELETE(handle, mem_ctx,
789 base_path, snap_path);
792 tmp_ctx = talloc_new(mem_ctx);
793 if (tmp_ctx == NULL) {
794 return NT_STATUS_NO_MEMORY;
797 dest_path = talloc_strdup(tmp_ctx, snap_path);
798 if (dest_path == NULL) {
799 talloc_free(tmp_ctx);
800 return NT_STATUS_NO_MEMORY;
802 subvolume = talloc_strdup(tmp_ctx, snap_path);
803 if (subvolume == NULL) {
804 talloc_free(tmp_ctx);
805 return NT_STATUS_NO_MEMORY;
807 dest_path = dirname(dest_path);
808 subvolume = basename(subvolume);
810 /* confirm snap_path matches creation format */
811 tstr = strptime(subvolume, SHADOW_COPY_PATH_FORMAT, &t_gmt);
812 if ((tstr == NULL) || (*tstr != '\0')) {
813 DEBUG(0, ("snapshot path %s does not match creation format\n",
815 talloc_free(tmp_ctx);
816 return NT_STATUS_UNSUCCESSFUL;
819 dest_dir = opendir(dest_path);
820 if (dest_dir == NULL) {
821 DEBUG(0, ("snap destroy dest %s open failed: %s\n",
822 dest_path, strerror(errno)));
823 status = map_nt_error_from_unix(errno);
824 talloc_free(tmp_ctx);
827 dest_fd = dirfd(dest_dir);
829 status = map_nt_error_from_unix(errno);
831 talloc_free(tmp_ctx);
835 ioctl_arg.fd = -1; /* not needed */
836 len = strlcpy(ioctl_arg.name, subvolume, ARRAY_SIZE(ioctl_arg.name));
837 if (len >= ARRAY_SIZE(ioctl_arg.name)) {
838 DEBUG(1, ("subvolume name too long for SNAP_DESTROY ioctl\n"));
840 talloc_free(tmp_ctx);
841 return NT_STATUS_INVALID_PARAMETER;
845 ret = ioctl(dest_fd, BTRFS_IOC_SNAP_DESTROY, &ioctl_arg);
849 DEBUG(0, ("%s(%s) BTRFS_IOC_SNAP_DESTROY failed: %s\n",
850 dest_path, subvolume, strerror(saved_errno)));
851 status = map_nt_error_from_unix(saved_errno);
853 talloc_free(tmp_ctx);
856 DEBUG(5, ("%s(%s) BTRFS_IOC_SNAP_DESTROY done\n",
857 dest_path, subvolume));
860 talloc_free(tmp_ctx);
864 static struct vfs_fn_pointers btrfs_fns = {
865 .fs_capabilities_fn = btrfs_fs_capabilities,
866 .offload_read_send_fn = btrfs_offload_read_send,
867 .offload_read_recv_fn = btrfs_offload_read_recv,
868 .offload_write_send_fn = btrfs_offload_write_send,
869 .offload_write_recv_fn = btrfs_offload_write_recv,
870 .fget_compression_fn = btrfs_fget_compression,
871 .set_compression_fn = btrfs_set_compression,
872 .snap_check_path_fn = btrfs_snap_check_path,
873 .snap_create_fn = btrfs_snap_create,
874 .snap_delete_fn = btrfs_snap_delete,
878 NTSTATUS vfs_btrfs_init(TALLOC_CTX *ctx)
880 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
881 "btrfs", &btrfs_fns);