Efficient xattr handling for VxFS Signed-off-by: Abhidnya Joshi <Abhidnya.Joshi@verit...
authorAbhidnya Joshi <Abhidnya.Joshi@veritas.com>
Thu, 2 Jun 2016 06:38:31 +0000 (23:38 -0700)
committerJeremy Allison <jra@samba.org>
Fri, 3 Jun 2016 05:26:33 +0000 (07:26 +0200)
Reviewed-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Fri Jun  3 07:26:34 CEST 2016 on sn-devel-144

source3/modules/lib_vxfs.c [new file with mode: 0644]
source3/modules/vfs_vxfs.c
source3/modules/vfs_vxfs.h [new file with mode: 0644]
source3/modules/wscript_build

diff --git a/source3/modules/lib_vxfs.c b/source3/modules/lib_vxfs.c
new file mode 100644 (file)
index 0000000..0d5ea60
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ Unix SMB/CIFS implementation.
+ Wrap VxFS xattr calls.
+
+ Copyright (C) Veritas Technologies LLC <www.veritas.com> 2016
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "smbd/smbd.h"
+#include "system/filesys.h"
+#include "string.h"
+
+/*
+ * Available under GPL at
+ * http://www.veritas.com/community/downloads/vxfsmisc-library
+ */
+#define LIBVXFS "/usr/lib64/vxfsmisc.so"
+
+
+static int (*vxfs_setxattr_fd_func) (int fd, const char *name,
+                                    const void *value, size_t len, int flags);
+static int (*vxfs_getxattr_fd_func) (int fd, const char *name, void *value,
+                                    size_t *len);
+static int (*vxfs_removexattr_fd_func) (int fd, const char *name);
+static int (*vxfs_listxattr_fd_func) (int fd, void *value, size_t *len);
+
+int vxfs_setxattr_fd(int fd, const char *name, const void *value,
+                    size_t len, int flags)
+{
+       int ret = -1;
+
+       if (vxfs_setxattr_fd_func == NULL) {
+               errno = ENOSYS;
+               return ret;
+       }
+
+       DEBUG(10, ("Calling vxfs_setxattr_fd\n"));
+       ret = vxfs_setxattr_fd_func(fd, name, value, len, flags);
+       if (ret) {
+               errno = ret;
+               ret = -1;
+       }
+
+       return ret;
+}
+
+int vxfs_setxattr_path(const char *path, const char *name, const void *value,
+                      size_t len, int flags, bool is_dir)
+{
+       int ret, fd = -1;
+
+       if (is_dir) {
+               fd = open(path, O_RDONLY|O_DIRECTORY);
+       } else {
+               fd = open(path, O_WRONLY);
+       }
+
+       if (fd == -1) {
+               DEBUG(10, ("error in vxfs_setxattr_path: %s\n",
+                     strerror(errno)));
+               return -1;
+       }
+
+       ret = vxfs_setxattr_fd(fd, name, value, len, flags);
+
+       close(fd);
+
+       return ret;
+}
+
+int vxfs_getxattr_fd(int fd, const char *name, void *value, size_t len)
+{
+       int ret;
+       size_t size = len;
+
+       if (vxfs_getxattr_fd_func == NULL) {
+               errno = ENOSYS;
+               return -1;
+       }
+
+       DEBUG(10, ("Calling vxfs_getxattr_fd with %s\n", name));
+       ret = vxfs_getxattr_fd_func(fd, name, value, &size);
+       if (ret) {
+               errno = ret;
+               if (ret == EFBIG) {
+                       errno = ERANGE;
+               }
+               return -1;
+       }
+
+       return size;
+}
+
+int vxfs_getxattr_path(const char *path, const char *name, void *value,
+                      size_t len)
+{
+       int ret, fd = -1;
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1) {
+               DEBUG(10, ("file not opened: vxfs_getxattr_path for %s\n",
+                          path));
+               return -1;
+       }
+
+       ret = vxfs_getxattr_fd(fd, name, value, len);
+       close(fd);
+
+       return ret;
+}
+
+int vxfs_removexattr_fd(int fd, const char *name)
+{
+       int ret = 0;
+
+       if (vxfs_removexattr_fd_func == NULL) {
+               errno = ENOSYS;
+               return -1;
+       }
+
+       DEBUG(10, ("Calling vxfs_removexattr_fd with %s\n", name));
+       ret = vxfs_removexattr_fd_func(fd, name);
+       if (ret) {
+               errno = ret;
+               ret = -1;
+       }
+
+       return ret;
+}
+
+int vxfs_removexattr_path(const char *path, const char *name, bool is_dir)
+{
+       int ret, fd = -1;
+
+       if (is_dir) {
+               fd = open(path, O_RDONLY|O_DIRECTORY);
+       } else {
+               fd = open(path, O_WRONLY);
+       }
+       if (fd == -1) {
+               DEBUG(10, ("file not opened: vxfs_removexattr_path for %s\n",
+                          path));
+               return -1;
+       }
+
+       ret = vxfs_removexattr_fd(fd, name);
+       close(fd);
+
+       return ret;
+}
+
+int vxfs_listxattr_fd(int fd, char *list, size_t size)
+{
+       int ret;
+       size_t len = size;
+
+       if (vxfs_listxattr_fd_func == NULL) {
+               errno = ENOSYS;
+               return -1;
+       }
+
+       ret = vxfs_listxattr_fd_func(fd, list, &len);
+       DEBUG(10, ("vxfs_listxattr_fd: returned ret = %d\n", ret));
+       if (ret) {
+               errno = ret;
+               if (ret == EFBIG) {
+                       errno = ERANGE;
+               }
+               return -1;
+       }
+
+       return len;
+}
+
+int vxfs_listxattr_path(const char *path, char *list, size_t size)
+{
+       int ret, fd = -1;
+
+       fd = open(path, O_RDONLY);
+       if (fd == -1) {
+               DEBUG(10, ("file not opened: vxfs_listxattr_path for %s\n",
+                          path));
+               return -1;
+       }
+
+       ret = vxfs_listxattr_fd(fd, list, size);
+       close(fd);
+
+       return ret;
+}
+
+static bool load_lib_vxfs_function(void *lib_handle, void *fn_ptr,
+                                  const char *fnc_name)
+{
+       void **vlib_handle = (void **)lib_handle;
+       void **fn_pointer = (void **)fn_ptr;
+
+       *fn_pointer = dlsym(*vlib_handle, fnc_name);
+       if (*fn_pointer == NULL) {
+               DEBUG(10, ("Cannot find symbol for %s\n", fnc_name));
+               return true;
+       }
+
+       return false;
+}
+
+void vxfs_init()
+{
+       static void *lib_handle = NULL;
+
+       if (lib_handle != NULL ) {
+               return;
+       }
+
+       lib_handle = dlopen(LIBVXFS, RTLD_LAZY);
+       if (lib_handle == NULL) {
+               DEBUG(10, ("Cannot get lib handle\n"));
+               return;
+       }
+
+       DEBUG(10, ("Calling vxfs_init\n"));
+       load_lib_vxfs_function(&lib_handle, &vxfs_setxattr_fd_func,
+                              "vxfs_nxattr_set");
+       load_lib_vxfs_function(&lib_handle, &vxfs_getxattr_fd_func,
+                              "vxfs_nxattr_get");
+       load_lib_vxfs_function(&lib_handle, &vxfs_removexattr_fd_func,
+                              "vxfs_nxattr_remove");
+       load_lib_vxfs_function(&lib_handle, &vxfs_listxattr_fd_func,
+                              "vxfs_nxattr_list");
+
+}
index bcd7ae3a91f44f7551680ad667d68749b7a756d9..feb3d49a3e66f05e415f072262c2d20d5f53c5e2 100644 (file)
@@ -1,9 +1,10 @@
 /*
 Unix SMB/CIFS implementation.
 Wrap VxFS calls in vfs functions.
-This module is for ACL handling.
+This module is for ACL and XATTR handling.
 
 Copyright (C) Symantec Corporation <www.symantec.com> 2014
+Copyright (C) Veritas Technologies LLC <www.veritas.com> 2016
 
 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
@@ -25,6 +26,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include "../libcli/security/security.h"
 #include "../librpc/gen_ndr/ndr_security.h"
 #include "system/filesys.h"
+#include "vfs_vxfs.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -509,9 +511,42 @@ static int vxfs_sys_acl_set_file(vfs_handle_struct *handle,  const char *name,
 static int vxfs_set_xattr(struct vfs_handle_struct *handle,  const char *path,
                          const char *name, const void *value, size_t size,
                          int flags){
+       struct smb_filename *smb_fname;
+       bool is_dir = false;
+       int ret = 0;
 
        DEBUG(10, ("In vxfs_set_xattr\n"));
 
+       smb_fname = synthetic_smb_fname(talloc_tos(), path, NULL, NULL, 0);
+       if (smb_fname == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       if (SMB_VFS_NEXT_STAT(handle, smb_fname) != 0) {
+               TALLOC_FREE(smb_fname);
+               return -1;
+       }
+
+       is_dir = S_ISDIR(smb_fname->st.st_ex_mode);
+       TALLOC_FREE(smb_fname);
+
+       ret = vxfs_setxattr_path(path, name, value, size, flags,
+                                 is_dir);
+       if ((ret == 0) ||
+           ((ret == -1) && (errno != ENOTSUP) && (errno != ENOSYS))) {
+               /*
+                * Now remve old style xattr if it exists
+                */
+               SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
+               /*
+                * Do not bother about return value
+                */
+
+               return ret;
+       }
+
+       DEBUG(10, ("Fallback to xattr\n"));
        if (strcmp(name, XATTR_NTACL_NAME) == 0) {
                return SMB_VFS_NEXT_SETXATTR(handle, path, XATTR_USER_NTACL,
                                             value, size, flags);
@@ -529,9 +564,18 @@ static int vxfs_set_xattr(struct vfs_handle_struct *handle,  const char *path,
 static int vxfs_fset_xattr(struct vfs_handle_struct *handle,
                           struct files_struct *fsp, const char *name,
                           const void *value, size_t size,  int flags){
+       int ret = 0;
 
        DEBUG(10, ("In vxfs_fset_xattr\n"));
 
+       ret = vxfs_setxattr_fd(fsp->fh->fd, name, value, size, flags);
+       if ((ret == 0) ||
+           ((ret == -1) && (errno != ENOTSUP) && (errno != ENOSYS))) {
+               SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name);
+               return ret;
+       }
+
+       DEBUG(10, ("Fallback to xattr"));
        if (strcmp(name, XATTR_NTACL_NAME) == 0) {
                return SMB_VFS_NEXT_FSETXATTR(handle, fsp, XATTR_USER_NTACL,
                                              value, size, flags);
@@ -549,9 +593,16 @@ static int vxfs_fset_xattr(struct vfs_handle_struct *handle,
 static ssize_t vxfs_get_xattr(struct vfs_handle_struct *handle,
                              const char *path, const char *name,
                              void *value, size_t size){
+       int ret;
 
        DEBUG(10, ("In vxfs_get_xattr\n"));
+       ret = vxfs_getxattr_path(path, name, value, size);
+       if ((ret != -1) || ((errno != ENOTSUP) &&
+                           (errno != ENOSYS) && (errno != ENODATA))) {
+               return ret;
+       }
 
+       DEBUG(10, ("Fallback to xattr\n"));
        if (strcmp(name, XATTR_NTACL_NAME) == 0) {
                return SMB_VFS_NEXT_GETXATTR(handle, path, XATTR_USER_NTACL,
                                             value, size);
@@ -569,9 +620,17 @@ static ssize_t vxfs_get_xattr(struct vfs_handle_struct *handle,
 static ssize_t vxfs_fget_xattr(struct vfs_handle_struct *handle,
                               struct files_struct *fsp, const char *name,
                               void *value, size_t size){
+       int ret;
 
        DEBUG(10, ("In vxfs_fget_xattr\n"));
 
+       ret = vxfs_getxattr_fd(fsp->fh->fd, name, value, size);
+       if ((ret != -1) || ((errno != ENOTSUP) &&
+                           (errno != ENOSYS) && (errno != ENODATA))) {
+               return ret;
+       }
+
+       DEBUG(10, ("Fallback to xattr\n"));
        if (strcmp(name, XATTR_NTACL_NAME) == 0) {
                return SMB_VFS_NEXT_FGETXATTR(handle, fsp, XATTR_USER_NTACL,
                                              value, size);
@@ -588,38 +647,86 @@ static ssize_t vxfs_fget_xattr(struct vfs_handle_struct *handle,
 
 static int vxfs_remove_xattr(struct vfs_handle_struct *handle,
                             const char *path, const char *name){
+       struct smb_filename *smb_fname;
+       bool is_dir = false;
+       int ret = 0, ret_new = 0, old_errno;
 
        DEBUG(10, ("In vxfs_remove_xattr\n"));
 
+       /* Remove with old way */
        if (strcmp(name, XATTR_NTACL_NAME) == 0) {
-               return SMB_VFS_NEXT_REMOVEXATTR(handle, path, XATTR_USER_NTACL);
+               ret = SMB_VFS_NEXT_REMOVEXATTR(handle, path,
+                                              XATTR_USER_NTACL);
+       } else {
+               if (strcasecmp(name, XATTR_USER_NTACL) != 0) {
+                       ret = SMB_VFS_NEXT_REMOVEXATTR(handle, path,
+                                                      name);
+               }
        }
+       old_errno = errno;
 
-       /* Clients can't see XATTR_USER_NTACL directly. */
-       if (strcasecmp(name, XATTR_USER_NTACL) == 0) {
-               errno = ENOATTR;
+       /* Remove with new way */
+       smb_fname = synthetic_smb_fname(talloc_tos(), path, NULL, NULL, 0);
+       if (smb_fname == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       if (SMB_VFS_NEXT_STAT(handle, smb_fname) != 0) {
+               TALLOC_FREE(smb_fname);
                return -1;
        }
 
-       return SMB_VFS_NEXT_REMOVEXATTR(handle, path, name);
+       is_dir = S_ISDIR(smb_fname->st.st_ex_mode);
+       TALLOC_FREE(smb_fname);
+       /*
+        * If both fail, return failuer else return whichever succeeded
+        */
+       ret_new = vxfs_removexattr_path(path, name, is_dir);
+       if (errno == ENOTSUP || errno == ENOSYS) {
+               errno = old_errno;
+       }
+       if ((ret_new != -1) && (ret == -1)) {
+               ret = ret_new;
+       }
+
+       return ret;
+
 }
 
 static int vxfs_fremove_xattr(struct vfs_handle_struct *handle,
                              struct files_struct *fsp, const char *name){
+       int ret = 0, ret_new = 0, old_errno;
 
        DEBUG(10, ("In vxfs_fremove_xattr\n"));
 
+       /* Remove with old way */
        if (strcmp(name, XATTR_NTACL_NAME) == 0) {
-               return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, XATTR_USER_NTACL);
+               ret = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp,
+                                               XATTR_USER_NTACL);
+       } else {
+               /* Clients can't remove XATTR_USER_NTACL directly. */
+               if (strcasecmp(name, XATTR_USER_NTACL) != 0) {
+                       ret = SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp,
+                                                       name);
+               }
        }
+       old_errno = errno;
 
-       /* Clients can't remove XATTR_USER_NTACL directly. */
-       if (strcasecmp(name, XATTR_USER_NTACL) == 0) {
-               errno = ENOATTR;
-               return -1;
+       /* Remove with new way */
+       ret_new = vxfs_removexattr_fd(fsp->fh->fd, name);
+       /*
+        * If both fail, return failuer else return whichever succeeded
+        */
+       if (errno == ENOTSUP || errno == ENOSYS) {
+               errno = old_errno;
+       }
+       if ((ret_new != -1) && (ret == -1)) {
+               ret = ret_new;
        }
 
-       return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name);
+       return ret;
+
 }
 
 static size_t vxfs_filter_list(char *list, size_t size)
@@ -645,6 +752,11 @@ static ssize_t vxfs_listxattr(vfs_handle_struct *handle, const char *path,
 {
        ssize_t result;
 
+       result = vxfs_listxattr_path(path, list, size);
+       if (result >= 0 || ((errno != ENOTSUP) && (errno != ENOSYS))) {
+               return result;
+       }
+
        result = SMB_VFS_NEXT_LISTXATTR(handle, path, list, size);
 
        if (result <= 0) {
@@ -663,6 +775,11 @@ static ssize_t vxfs_flistxattr(struct vfs_handle_struct *handle,
 {
        ssize_t result;
 
+       result = vxfs_listxattr_fd(fsp->fh->fd, list, size);
+       if (result >= 0 || ((errno != ENOTSUP) && (errno != ENOSYS))) {
+               return result;
+       }
+
        result = SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
 
        if (result <= 0) {
@@ -679,19 +796,25 @@ static int vfs_vxfs_connect(struct vfs_handle_struct *handle,
                            const char *service, const char *user)
 {
 
-       int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
+       int ret;
 
+       ret  = SMB_VFS_NEXT_CONNECT(handle, service, user);
        if (ret < 0) {
                return ret;
        }
+
+       vxfs_init();
+
        return 0;
 }
 
 static struct vfs_fn_pointers vfs_vxfs_fns = {
        .connect_fn = vfs_vxfs_connect,
 
+#ifdef VXFS_ACL_SHARE
        .sys_acl_set_file_fn = vxfs_sys_acl_set_file,
        .sys_acl_set_fd_fn = vxfs_sys_acl_set_fd,
+#endif
 
        .getxattr_fn = vxfs_get_xattr,
        .fgetxattr_fn = vxfs_fget_xattr,
diff --git a/source3/modules/vfs_vxfs.h b/source3/modules/vfs_vxfs.h
new file mode 100644 (file)
index 0000000..55a4dae
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+Unix SMB/CIFS implementation.
+Wrap VxFS xattr calls in vfs functions.
+
+Copyright (C) Veritas Technologies LLC <www.veritas.com> 2016
+
+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 <http://www.gnu.org/licenses/>.
+*/
+
+int vxfs_setxattr_path(const char *, const char *, const void *, size_t, int,
+                      bool);
+int vxfs_setxattr_fd(int, const char *, const void *, size_t, int);
+
+int vxfs_getxattr_path(const char *, const char *, void *, size_t);
+int vxfs_getxattr_fd(int, const char *, void *, size_t);
+
+int vxfs_removexattr_path(const char *, const char *, bool);
+int vxfs_removexattr_fd(int, const char *);
+
+int vxfs_listxattr_path(const char *, char *, size_t);
+int vxfs_listxattr_fd(int, char *, size_t);
+
+void vxfs_init(void);
index 77b28f64b5641d798760ae8e95e026a117f2675c..03794f474e00b40c2e7e79313fba083362708eeb 100644 (file)
@@ -479,7 +479,7 @@ bld.SAMBA3_MODULE('vfs_snapper',
 
 bld.SAMBA3_MODULE('vfs_vxfs',
                  subsystem='vfs',
-                 source='vfs_vxfs.c',
+                 source='lib_vxfs.c vfs_vxfs.c',
                  init_function='',
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_vxfs'),
                  enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_vxfs'))