From 15ce3a9c2f2aedcd4896235238a4ffdf23aa9178 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Fri, 8 Mar 2013 11:47:55 +0100 Subject: [PATCH] s3-vfs: add vfs_btrfs module Currently it only plumbs itself into the copy_chunk call path, translating such requests into BTRFS_IOC_CLONE_RANGE calls. Reviewed-by: Andrew Bartlett --- source3/Makefile.in | 5 ++ source3/configure.in | 8 ++ source3/modules/vfs_btrfs.c | 196 ++++++++++++++++++++++++++++++++++++++++++ source3/modules/wscript_build | 9 ++ source3/wscript | 6 ++ 5 files changed, 224 insertions(+) create mode 100644 source3/modules/vfs_btrfs.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 4b6918a838b..576cce9bd81 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -906,6 +906,7 @@ VFS_CROSSRENAME_OBJ = modules/vfs_crossrename.o VFS_LINUX_XFS_SGID_OBJ = modules/vfs_linux_xfs_sgid.o VFS_TIME_AUDIT_OBJ = modules/vfs_time_audit.o VFS_MEDIA_HARMONY_OBJ = modules/vfs_media_harmony.o +VFS_BTRFS_OBJ = modules/vfs_btrfs.o PAM_ERRORS_OBJ = ../libcli/auth/pam_errors.o PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o $(PAM_ERRORS_OBJ) @@ -2917,6 +2918,10 @@ bin/media_harmony.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_MEDIA_HARMONY_OBJ) @echo "Building plugin $@" @$(SHLD_MODULE) $(VFS_MEDIA_HARMONY_OBJ) +bin/btrfs.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_BTRFS_OBJ) + @echo "Building plugin $@" + @$(SHLD_MODULE) $(VFS_BTRFS_OBJ) + ######################################################### ## IdMap NSS plugins diff --git a/source3/configure.in b/source3/configure.in index 552535bfafe..8c3b36cc55d 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -606,6 +606,7 @@ AC_CHECK_HEADERS(xfs/libxfs.h) AC_CHECK_HEADERS(netgroup.h) AC_CHECK_HEADERS(linux/falloc.h) AC_CHECK_HEADERS(CommonCrypto/CommonDigest.h) +AC_CHECK_HEADERS(linux/ioctl.h) dnl check for OS implementation of md5 conformant to rfc1321 samba_cv_md5lib=none @@ -6312,6 +6313,12 @@ fi # End # Checks for the vfs_fileid module +# btrfs features are dependent on Linux ioctl headers +if test x"$ac_cv_header_sys_ioctl_h" = xyes -a \ + x"$ac_cv_header_linux_ioctl_h" = xyes; then + default_shared_modules="$default_shared_modules vfs_btrfs" +fi +# End btrfs for i in `echo $default_static_modules | sed -e 's/,/ /g'` do @@ -6446,6 +6453,7 @@ SMB_MODULE(vfs_crossrename, \$(VFS_CROSSRENAME_OBJ), "bin/crossrename.$SHLIBEXT" SMB_MODULE(vfs_linux_xfs_sgid, \$(VFS_LINUX_XFS_SGID_OBJ), "bin/linux_xfs_sgid.$SHLIBEXT", VFS) SMB_MODULE(vfs_time_audit, \$(VFS_TIME_AUDIT_OBJ), "bin/time_audit.$SHLIBEXT", VFS) SMB_MODULE(vfs_media_harmony, \$(VFS_MEDIA_HARMONY_OBJ), "bin/media_harmony.$SHLIBEXT", VFS) +SMB_MODULE(vfs_btrfs, \$(VFS_BTRFS_OBJ), "bin/btrfs.$SHLIBEXT", VFS) SMB_SUBSYSTEM(VFS,smbd/vfs.o) diff --git a/source3/modules/vfs_btrfs.c b/source3/modules/vfs_btrfs.c new file mode 100644 index 00000000000..660bc680634 --- /dev/null +++ b/source3/modules/vfs_btrfs.c @@ -0,0 +1,196 @@ +/* + * Module to make use of awesome Btrfs features + * + * Copyright (C) David Disseldorp 2011-2013 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include "includes.h" +#include "system/filesys.h" +#include "smbd/smbd.h" +#include "../librpc/gen_ndr/smbXsrv.h" +#include "lib/util/tevent_ntstatus.h" + +struct btrfs_ioctl_clone_range_args { + int64_t src_fd; + uint64_t src_offset; + uint64_t src_length; + uint64_t dest_offset; +}; + +#define BTRFS_IOCTL_MAGIC 0x94 +#define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \ + struct btrfs_ioctl_clone_range_args) + +struct btrfs_cc_state { + struct vfs_handle_struct *handle; + off_t copied; + struct tevent_req *subreq; /* non-null if passed to next VFS fn */ +}; +static void btrfs_copy_chunk_done(struct tevent_req *subreq); + +static struct tevent_req *btrfs_copy_chunk_send(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct files_struct *src_fsp, + off_t src_off, + struct files_struct *dest_fsp, + off_t dest_off, + off_t num) +{ + struct tevent_req *req; + struct btrfs_cc_state *cc_state; + struct btrfs_ioctl_clone_range_args cr_args; + struct lock_struct src_lck; + struct lock_struct dest_lck; + int ret; + NTSTATUS status; + + req = tevent_req_create(mem_ctx, &cc_state, struct btrfs_cc_state); + if (req == NULL) { + return NULL; + } + cc_state->handle = handle; + + status = vfs_stat_fsp(src_fsp); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + if (src_fsp->fsp_name->st.st_ex_size < src_off + num) { + /* [MS-SMB2] Handling a Server-Side Data Copy Request */ + tevent_req_nterror(req, NT_STATUS_INVALID_VIEW_SIZE); + return tevent_req_post(req, ev); + } + + init_strict_lock_struct(src_fsp, + src_fsp->op->global->open_persistent_id, + src_off, + num, + READ_LOCK, + &src_lck); + init_strict_lock_struct(dest_fsp, + dest_fsp->op->global->open_persistent_id, + dest_off, + num, + WRITE_LOCK, + &dest_lck); + + if (!SMB_VFS_STRICT_LOCK(src_fsp->conn, src_fsp, &src_lck)) { + tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); + return tevent_req_post(req, ev); + } + if (!SMB_VFS_STRICT_LOCK(dest_fsp->conn, dest_fsp, &dest_lck)) { + SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &src_lck); + tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT); + return tevent_req_post(req, ev); + } + + ZERO_STRUCT(cr_args); + cr_args.src_fd = src_fsp->fh->fd; + cr_args.src_offset = (uint64_t)src_off; + cr_args.dest_offset = (uint64_t)dest_off; + cr_args.src_length = (uint64_t)num; + + ret = ioctl(dest_fsp->fh->fd, BTRFS_IOC_CLONE_RANGE, &cr_args); + SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &dest_lck); + SMB_VFS_STRICT_UNLOCK(src_fsp->conn, src_fsp, &src_lck); + if (ret < 0) { + /* + * BTRFS_IOC_CLONE_RANGE only supports 'sectorsize' aligned + * cloning. Which is 4096 by default, therefore fall back to + * manual read/write on failure. + */ + DEBUG(5, ("BTRFS_IOC_CLONE_RANGE failed: %s, length %lu, " + "src fd: %ld off: %lu, dest fd: %d off: %lu\n", + strerror(errno), cr_args.src_length, + cr_args.src_fd, cr_args.src_offset, + dest_fsp->fh->fd, cr_args.dest_offset)); + cc_state->subreq = SMB_VFS_NEXT_COPY_CHUNK_SEND(handle, + cc_state, ev, + src_fsp, + src_off, + dest_fsp, + dest_off, num); + if (tevent_req_nomem(cc_state->subreq, req)) { + return tevent_req_post(req, ev); + } + /* wait for subreq completion */ + tevent_req_set_callback(cc_state->subreq, + btrfs_copy_chunk_done, + req); + return req; + + } + + DEBUG(5, ("BTRFS_IOC_CLONE_RANGE returned %d\n", ret)); + /* BTRFS_IOC_CLONE_RANGE is all or nothing */ + cc_state->copied = num; + tevent_req_done(req); + return tevent_req_post(req, ev); +} + +/* only used if the request is passed through to next VFS module */ +static void btrfs_copy_chunk_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct btrfs_cc_state *cc_state = tevent_req_data(req, + struct btrfs_cc_state); + NTSTATUS status; + + status = SMB_VFS_NEXT_COPY_CHUNK_RECV(cc_state->handle, + cc_state->subreq, + &cc_state->copied); + if (tevent_req_nterror(req, status)) { + return; + } + tevent_req_done(req); +} + +static NTSTATUS btrfs_copy_chunk_recv(struct vfs_handle_struct *handle, + struct tevent_req *req, + off_t *copied) +{ + NTSTATUS status; + struct btrfs_cc_state *cc_state = tevent_req_data(req, + struct btrfs_cc_state); + + if (tevent_req_is_nterror(req, &status)) { + DEBUG(4, ("server side copy chunk failed: %s\n", + nt_errstr(status))); + tevent_req_received(req); + return status; + } + + DEBUG(10, ("server side copy chunk copied %lu\n", cc_state->copied)); + *copied = cc_state->copied; + tevent_req_received(req); + return NT_STATUS_OK; +} + +static struct vfs_fn_pointers btrfs_fns = { + .copy_chunk_send_fn = btrfs_copy_chunk_send, + .copy_chunk_recv_fn = btrfs_copy_chunk_recv, +}; + +NTSTATUS vfs_btrfs_init(void); +NTSTATUS vfs_btrfs_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, + "btrfs", &btrfs_fns); +} diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build index 43daaf079ed..ef5748ceef6 100644 --- a/source3/modules/wscript_build +++ b/source3/modules/wscript_build @@ -49,6 +49,7 @@ VFS_CROSSRENAME_SRC = 'vfs_crossrename.c' VFS_LINUX_XFS_SGID_SRC = 'vfs_linux_xfs_sgid.c' VFS_TIME_AUDIT_SRC = 'vfs_time_audit.c' VFS_MEDIA_HARMONY_SRC = 'vfs_media_harmony.c' +VFS_BTRFS_SRC = 'vfs_btrfs.c' bld.SAMBA3_SUBSYSTEM('NFS4_ACLS', @@ -478,6 +479,14 @@ bld.SAMBA3_MODULE('vfs_dfs_samba4', internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_dfs_samba4') and bld.AD_DC_BUILD_IS_ENABLED(), enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_dfs_samba4') and bld.AD_DC_BUILD_IS_ENABLED()) +bld.SAMBA3_MODULE('vfs_btrfs', + subsystem='vfs', + source=VFS_BTRFS_SRC, + deps='samba-util', + init_function='', + internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_btrfs'), + enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_btrfs')) + PERFCOUNT_TEST_SRC = 'perfcount_test.c' bld.SAMBA3_SUBSYSTEM('perfcount', diff --git a/source3/wscript b/source3/wscript index 1bc68115e52..42f532d9dbe 100644 --- a/source3/wscript +++ b/source3/wscript @@ -1669,6 +1669,9 @@ main() { if conf.CHECK_HEADERS('gpfs_gpl.h'): conf.DEFINE('HAVE_GPFS', '1') + if conf.CHECK_HEADERS('linux/ioctl.h sys/ioctl.h'): + conf.DEFINE('HAVE_LINUX_IOCTL', '1') + default_static_modules.extend(TO_LIST('''pdb_smbpasswd pdb_tdbsam pdb_wbc_sam auth_sam auth_unix auth_winbind auth_wbc auth_domain auth_builtin vfs_default @@ -1730,6 +1733,9 @@ main() { if conf.CONFIG_SET('HAVE_GPFS'): default_shared_modules.extend(TO_LIST('vfs_gpfs')) + if conf.CONFIG_SET('HAVE_LINUX_IOCTL'): + default_shared_modules.extend(TO_LIST('vfs_btrfs')) + explicit_shared_modules = TO_LIST(Options.options.shared_modules, delimiter=',') explicit_static_modules = TO_LIST(Options.options.static_modules, delimiter=',') -- 2.11.4.GIT