From 433d1b5816a9a2befdf86c806f1ae79f7d35bef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Jacke?= Date: Mon, 8 Mar 2010 12:52:13 +0100 Subject: [PATCH 1/3] s3: remove cross-device rename support from vfs_default cross-device rename support has some major limitations: - on huge files clients will timeout or hang - ACLs and EA information is not retained Usually a client will have to handle this. A Windows Server with a reparse point will also just return NT_STATUS_NOT_SAME_DEVICE. We will now by default do the same. I will add a vfs module which will restore the old cross-device renames. --- source3/modules/vfs_default.c | 116 ----------------------------------------- 1 files changed, 0 insertions(+), 116 deletions(-) diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 6e2a571..faca292 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -475,117 +475,6 @@ static ssize_t vfswrap_recvfile(vfs_handle_struct *handle, return result; } -/********************************************************* - For rename across filesystems Patch from Warren Birnbaum - -**********************************************************/ - -static int copy_reg(const char *source, const char *dest) -{ - SMB_STRUCT_STAT source_stats; - int saved_errno; - int ifd = -1; - int ofd = -1; - - if (sys_lstat(source, &source_stats, false) == -1) - return -1; - - if (!S_ISREG (source_stats.st_ex_mode)) - return -1; - - if((ifd = sys_open (source, O_RDONLY, 0)) < 0) - return -1; - - if (unlink (dest) && errno != ENOENT) - return -1; - -#ifdef O_NOFOLLOW - if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0600)) < 0 ) -#else - if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC , 0600)) < 0 ) -#endif - goto err; - - if (transfer_file(ifd, ofd, (size_t)-1) == -1) - goto err; - - /* - * Try to preserve ownership. For non-root it might fail, but that's ok. - * But root probably wants to know, e.g. if NFS disallows it. - */ - -#ifdef HAVE_FCHOWN - if ((fchown(ofd, source_stats.st_ex_uid, source_stats.st_ex_gid) == -1) && (errno != EPERM)) -#else - if ((chown(dest, source_stats.st_ex_uid, source_stats.st_ex_gid) == -1) && (errno != EPERM)) -#endif - goto err; - - /* - * fchown turns off set[ug]id bits for non-root, - * so do the chmod last. - */ - -#if defined(HAVE_FCHMOD) - if (fchmod (ofd, source_stats.st_ex_mode & 07777)) -#else - if (chmod (dest, source_stats.st_ex_mode & 07777)) -#endif - goto err; - - if (close (ifd) == -1) - goto err; - - if (close (ofd) == -1) - return -1; - - /* Try to copy the old file's modtime and access time. */ -#if defined(HAVE_UTIMENSAT) - { - struct timespec ts[2]; - - ts[0] = source_stats.st_ex_atime; - ts[1] = source_stats.st_ex_mtime; - utimensat(AT_FDCWD, dest, ts, AT_SYMLINK_NOFOLLOW); - } -#elif defined(HAVE_UTIMES) - { - struct timeval tv[2]; - - tv[0] = convert_timespec_to_timeval(source_stats.st_ex_atime); - tv[1] = convert_timespec_to_timeval(source_stats.st_ex_mtime); -#ifdef HAVE_LUTIMES - lutimes(dest, tv); -#else - utimes(dest, tv); -#endif - } -#elif defined(HAVE_UTIME) - { - struct utimbuf tv; - - tv.actime = convert_timespec_to_time_t(source_stats.st_ex_atime); - tv.modtime = convert_timespec_to_time_t(source_stats.st_ex_mtime); - utime(dest, &tv); - } -#endif - - if (unlink (source) == -1) - return -1; - - return 0; - - err: - - saved_errno = errno; - if (ifd != -1) - close(ifd); - if (ofd != -1) - close(ofd); - errno = saved_errno; - return -1; -} - static int vfswrap_rename(vfs_handle_struct *handle, const struct smb_filename *smb_fname_src, const struct smb_filename *smb_fname_dst) @@ -600,11 +489,6 @@ static int vfswrap_rename(vfs_handle_struct *handle, } result = rename(smb_fname_src->base_name, smb_fname_dst->base_name); - if ((result == -1) && (errno == EXDEV)) { - /* Rename across filesystems needed. */ - result = copy_reg(smb_fname_src->base_name, - smb_fname_dst->base_name); - } out: END_PROFILE(syscall_rename); -- 1.6.6.1 From 6dc931b27daf06aa1f4cdca19dae44ffef0bc3fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Jacke?= Date: Mon, 8 Mar 2010 18:18:59 +0100 Subject: [PATCH 2/3] s3: add vfs_crossrename this module adds optional server-side support for limited rename operations beyond filesystem boundaries, which was the previously the default. --- source3/Makefile.in | 5 + source3/configure.in | 3 +- source3/modules/vfs_crossrename.c | 200 +++++++++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+), 1 deletions(-) create mode 100644 source3/modules/vfs_crossrename.c diff --git a/source3/Makefile.in b/source3/Makefile.in index f84ed20..2b90958 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -741,6 +741,7 @@ PERFCOUNT_ONEFS_OBJ = modules/perfcount_onefs.o PERFCOUNT_TEST_OBJ = modules/perfcount_test.o VFS_DIRSORT_OBJ = modules/vfs_dirsort.o VFS_SCANNEDONLY_OBJ = modules/vfs_scannedonly.o +VFS_CROSSRENAME_OBJ = modules/vfs_crossrename.o PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o @@ -2846,6 +2847,10 @@ bin/scannedonly.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SCANNEDONLY_OBJ) @echo "Building plugin $@" @$(SHLD_MODULE) $(VFS_SCANNEDONLY_OBJ) +bin/crossrename.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_CROSSRENAME_OBJ) + @echo "Building plugin $@" + @$(SHLD_MODULE) $(VFS_CROSSRENAME_OBJ) + ######################################################### ## IdMap NSS plugins diff --git a/source3/configure.in b/source3/configure.in index 0529a69..dbbc5be 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -387,7 +387,7 @@ dnl These have to be built static: default_static_modules="pdb_smbpasswd pdb_tdbsam pdb_wbc_sam rpc_lsarpc rpc_samr rpc_winreg rpc_initshutdown rpc_dssetup rpc_wkssvc rpc_svcctl rpc_ntsvcs rpc_netlogon rpc_netdfs rpc_srvsvc rpc_spoolss rpc_eventlog auth_sam auth_unix auth_winbind auth_wbc auth_server auth_domain auth_builtin auth_netlogond vfs_default nss_info_template" dnl These are preferably build shared, and static if dlopen() is not available -default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_xattr_tdb vfs_streams_xattr vfs_streams_depot vfs_acl_xattr vfs_acl_tdb vfs_smb_traffic_analyzer vfs_preopen vfs_catia vfs_scannedonly" +default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_xattr_tdb vfs_streams_xattr vfs_streams_depot vfs_acl_xattr vfs_acl_tdb vfs_smb_traffic_analyzer vfs_preopen vfs_catia vfs_scannedonly vfs_crossrename" if test "x$developer" = xyes; then default_static_modules="$default_static_modules rpc_rpcecho pdb_ads" @@ -6571,6 +6571,7 @@ SMB_MODULE(vfs_onefs, \$(VFS_ONEFS), "bin/onefs.$SHLIBEXT", VFS) SMB_MODULE(vfs_onefs_shadow_copy, \$(VFS_ONEFS_SHADOW_COPY), "bin/onefs_shadow_copy.$SHLIBEXT", VFS) SMB_MODULE(vfs_dirsort, \$(VFS_DIRSORT_OBJ), "bin/dirsort.$SHLIBEXT", VFS) SMB_MODULE(vfs_scannedonly, \$(VFS_SCANNEDONLY_OBJ), "bin/scannedonly.$SHLIBEXT", VFS) +SMB_MODULE(vfs_crossrename, \$(VFS_CROSSRENAME_OBJ), "bin/crossrename.$SHLIBEXT", VFS) SMB_SUBSYSTEM(VFS,smbd/vfs.o) diff --git a/source3/modules/vfs_crossrename.c b/source3/modules/vfs_crossrename.c new file mode 100644 index 0000000..323ceb1 --- /dev/null +++ b/source3/modules/vfs_crossrename.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) Björn Jacke 2010 + * + * 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 "includes.h" + + +#define MODULE "crossrename" +static SMB_OFF_T module_sizelimit; + +static int crossrename_connect( + struct vfs_handle_struct * handle, + const char * service, + const char * user) +{ + int ret = SMB_VFS_NEXT_CONNECT(handle, service, user); + + if (ret < 0) { + return ret; + } + + module_sizelimit = (SMB_OFF_T) lp_parm_int(SNUM(handle->conn), + MODULE, "sizelimit", 20); + /* convert from MiB to byte: */ + module_sizelimit *= 1048576; + + return 0; +} + +/********************************************************* + For rename across filesystems initial Patch from Warren Birnbaum + +**********************************************************/ + +static int copy_reg(const char *source, const char *dest) +{ + SMB_STRUCT_STAT source_stats; + int saved_errno; + int ifd = -1; + int ofd = -1; + + if (sys_lstat(source, &source_stats, false) == -1) + return -1; + + if (!S_ISREG (source_stats.st_ex_mode)) + return -1; + + if (source_stats.st_ex_size > module_sizelimit) { + DEBUG(5, + ("%s: size of %s larger than sizelimit (%lld > %lld), rename prohititted\n", + MODULE, source, + (long long)source_stats.st_ex_size, + (long long)module_sizelimit)); + return -1; + } + + if((ifd = sys_open (source, O_RDONLY, 0)) < 0) + return -1; + + if (unlink (dest) && errno != ENOENT) + return -1; + +#ifdef O_NOFOLLOW + if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0600)) < 0 ) +#else + if((ofd = sys_open (dest, O_WRONLY | O_CREAT | O_TRUNC , 0600)) < 0 ) +#endif + goto err; + + if (transfer_file(ifd, ofd, (size_t)-1) == -1) + goto err; + + /* + * Try to preserve ownership. For non-root it might fail, but that's ok. + * But root probably wants to know, e.g. if NFS disallows it. + */ + +#ifdef HAVE_FCHOWN + if ((fchown(ofd, source_stats.st_ex_uid, source_stats.st_ex_gid) == -1) && (errno != EPERM)) +#else + if ((chown(dest, source_stats.st_ex_uid, source_stats.st_ex_gid) == -1) && (errno != EPERM)) +#endif + goto err; + + /* + * fchown turns off set[ug]id bits for non-root, + * so do the chmod last. + */ + +#if defined(HAVE_FCHMOD) + if (fchmod (ofd, source_stats.st_ex_mode & 07777)) +#else + if (chmod (dest, source_stats.st_ex_mode & 07777)) +#endif + goto err; + + if (close (ifd) == -1) + goto err; + + if (close (ofd) == -1) + return -1; + + /* Try to copy the old file's modtime and access time. */ +#if defined(HAVE_UTIMENSAT) + { + struct timespec ts[2]; + + ts[0] = source_stats.st_ex_atime; + ts[1] = source_stats.st_ex_mtime; + utimensat(AT_FDCWD, dest, ts, AT_SYMLINK_NOFOLLOW); + } +#elif defined(HAVE_UTIMES) + { + struct timeval tv[2]; + + tv[0] = convert_timespec_to_timeval(source_stats.st_ex_atime); + tv[1] = convert_timespec_to_timeval(source_stats.st_ex_mtime); +#ifdef HAVE_LUTIMES + lutimes(dest, tv); +#else + utimes(dest, tv); +#endif + } +#elif defined(HAVE_UTIME) + { + struct utimbuf tv; + + tv.actime = convert_timespec_to_time_t(source_stats.st_ex_atime); + tv.modtime = convert_timespec_to_time_t(source_stats.st_ex_mtime); + utime(dest, &tv); + } +#endif + + if (unlink (source) == -1) + return -1; + + return 0; + + err: + + saved_errno = errno; + if (ifd != -1) + close(ifd); + if (ofd != -1) + close(ofd); + errno = saved_errno; + return -1; +} + + +static int crossrename_rename(vfs_handle_struct *handle, + const struct smb_filename *smb_fname_src, + const struct smb_filename *smb_fname_dst) +{ + int result = -1; + + START_PROFILE(syscall_rename); + + if (smb_fname_src->stream_name || smb_fname_dst->stream_name) { + errno = ENOENT; + goto out; + } + + result = rename(smb_fname_src->base_name, smb_fname_dst->base_name); + if ((result == -1) && (errno == EXDEV)) { + /* Rename across filesystems needed. */ + result = copy_reg(smb_fname_src->base_name, + smb_fname_dst->base_name); + } + + out: + END_PROFILE(syscall_rename); + return result; +} + +static struct vfs_fn_pointers vfs_crossrename_fns = { + .connect_fn = crossrename_connect, + .rename = crossrename_rename +}; + +NTSTATUS vfs_crossrename_init(void); +NTSTATUS vfs_crossrename_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, MODULE, + &vfs_crossrename_fns); +} + -- 1.6.6.1 From 555acebc72c2827691e91648f697212ffa6725d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Jacke?= Date: Mon, 8 Mar 2010 12:38:38 +0100 Subject: [PATCH 3/3] s3: add man page for vfs_crossrename --- docs-xml/manpages-3/vfs_crossrename.8.xml | 115 +++++++++++++++++++++++++++++ 1 files changed, 115 insertions(+), 0 deletions(-) create mode 100644 docs-xml/manpages-3/vfs_crossrename.8.xml diff --git a/docs-xml/manpages-3/vfs_crossrename.8.xml b/docs-xml/manpages-3/vfs_crossrename.8.xml new file mode 100644 index 0000000..675c92e --- /dev/null +++ b/docs-xml/manpages-3/vfs_crossrename.8.xml @@ -0,0 +1,115 @@ + + + + + + vfs_crossrename + 8 + Samba + System Administration tools + 3.6 + + + + + vfs_crossrename + server side rename files across filesystem boundaries + + + + + vfs objects = crossrename + + + + + DESCRIPTION + + This VFS module is part of the + samba + 7 suite. + + The vfs_crossrename VFS module allows + server side rename operations even if source and target are on + differen physical devices. A "move" in Explorer is usually a + rename operation if it is inside of a single share or device. + Usually such a rename operation returns + NT_STATUS_NOT_SAME_DEVICE and the client has to move the file by + manual copy and delete operations. If the rename by copy is done by the + server this can be much more efficient. vfs_crossrename tries to do + this server-side cross-device rename operation. There are however + limitations that this module currently does not solve: + + + + the ACLs of files are not preserved + + + meta data in EAs are not preserved + + + renames of whole subdirectories cannot be done recursively, + in that case we still return STATUS_NOT_SAME_DEVICE and + let the client decide what to do + + + rename operations of huge files can cause hangs on the + client because clients expect a rename operation to + return fast + + + + + This module is stackable. + + + + + + OPTIONS + + + + + crossrename:sizelimit = BYTES + + server-side cross-device-renames are only done + for files if the filesize is not larger than the defined + size in MiB to prevent timeouts. The default sizelimit is + 20 (MiB) + + + + + + + EXAMPLES + + To add server-side cross-device renames inside of a share + for all files sized up to 50MB: + + + + /data/mounts + crossrename + 50 + + + + + VERSION + This man page is correct for version 3.6.0 of the Samba suite. + + + + + AUTHOR + + The original Samba software and related utilities + were created by Andrew Tridgell. Samba is now developed + by the Samba Team as an Open Source project similar + to the way the Linux kernel is developed. + + + + -- 1.6.6.1