LCOV - code coverage report
Current view: top level - source3/modules - vfs_glusterfs.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 2 1055 0.2 %
Date: 2024-06-13 04:01:37 Functions: 1 79 1.3 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Wrap GlusterFS GFAPI calls in vfs functions.
       5             : 
       6             :    Copyright (c) 2013 Anand Avati <avati@redhat.com>
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : /**
      23             :  * @file   vfs_glusterfs.c
      24             :  * @author Anand Avati <avati@redhat.com>
      25             :  * @date   May 2013
      26             :  * @brief  Samba VFS module for glusterfs
      27             :  *
      28             :  * @todo
      29             :  *   - sendfile/recvfile support
      30             :  *
      31             :  * A Samba VFS module for GlusterFS, based on Gluster's libgfapi.
      32             :  * This is a "bottom" vfs module (not something to be stacked on top of
      33             :  * another module), and translates (most) calls to the closest actions
      34             :  * available in libgfapi.
      35             :  *
      36             :  */
      37             : 
      38             : #include "includes.h"
      39             : #include "smbd/smbd.h"
      40             : #include <stdio.h>
      41             : #include <glusterfs/api/glfs.h>
      42             : #include "lib/util/dlinklist.h"
      43             : #include "lib/util/tevent_unix.h"
      44             : #include "smbd/globals.h"
      45             : #include "lib/util/sys_rw.h"
      46             : #include "smbprofile.h"
      47             : #include "modules/posixacl_xattr.h"
      48             : #include "lib/pthreadpool/pthreadpool_tevent.h"
      49             : 
      50             : #define DEFAULT_VOLFILE_SERVER "localhost"
      51             : #define GLUSTER_NAME_MAX 255
      52             : 
      53             : /**
      54             :  * Helper to convert struct stat to struct stat_ex.
      55             :  */
      56           0 : static void smb_stat_ex_from_stat(struct stat_ex *dst, const struct stat *src)
      57             : {
      58           0 :         ZERO_STRUCTP(dst);
      59             : 
      60           0 :         dst->st_ex_dev = src->st_dev;
      61           0 :         dst->st_ex_ino = src->st_ino;
      62           0 :         dst->st_ex_mode = src->st_mode;
      63           0 :         dst->st_ex_nlink = src->st_nlink;
      64           0 :         dst->st_ex_uid = src->st_uid;
      65           0 :         dst->st_ex_gid = src->st_gid;
      66           0 :         dst->st_ex_rdev = src->st_rdev;
      67           0 :         dst->st_ex_size = src->st_size;
      68           0 :         dst->st_ex_atime.tv_sec = src->st_atime;
      69           0 :         dst->st_ex_mtime.tv_sec = src->st_mtime;
      70           0 :         dst->st_ex_ctime.tv_sec = src->st_ctime;
      71           0 :         dst->st_ex_btime.tv_sec = src->st_mtime;
      72           0 :         dst->st_ex_blksize = src->st_blksize;
      73           0 :         dst->st_ex_blocks = src->st_blocks;
      74             : #ifdef STAT_HAVE_NSEC
      75             :         dst->st_ex_atime.tv_nsec = src->st_atime_nsec;
      76             :         dst->st_ex_mtime.tv_nsec = src->st_mtime_nsec;
      77             :         dst->st_ex_ctime.tv_nsec = src->st_ctime_nsec;
      78             :         dst->st_ex_btime.tv_nsec = src->st_mtime_nsec;
      79             : #endif
      80           0 : }
      81             : 
      82             : /* pre-opened glfs_t */
      83             : 
      84             : static struct glfs_preopened {
      85             :         char *volume;
      86             :         char *connectpath;
      87             :         glfs_t *fs;
      88             :         int ref;
      89             :         struct glfs_preopened *next, *prev;
      90             : } *glfs_preopened;
      91             : 
      92             : 
      93           0 : static int glfs_set_preopened(const char *volume, const char *connectpath, glfs_t *fs)
      94             : {
      95           0 :         struct glfs_preopened *entry = NULL;
      96             : 
      97           0 :         entry = talloc_zero(NULL, struct glfs_preopened);
      98           0 :         if (!entry) {
      99           0 :                 errno = ENOMEM;
     100           0 :                 return -1;
     101             :         }
     102             : 
     103           0 :         entry->volume = talloc_strdup(entry, volume);
     104           0 :         if (!entry->volume) {
     105           0 :                 talloc_free(entry);
     106           0 :                 errno = ENOMEM;
     107           0 :                 return -1;
     108             :         }
     109             : 
     110           0 :         entry->connectpath = talloc_strdup(entry, connectpath);
     111           0 :         if (entry->connectpath == NULL) {
     112           0 :                 talloc_free(entry);
     113           0 :                 errno = ENOMEM;
     114           0 :                 return -1;
     115             :         }
     116             : 
     117           0 :         entry->fs = fs;
     118           0 :         entry->ref = 1;
     119             : 
     120           0 :         DLIST_ADD(glfs_preopened, entry);
     121             : 
     122           0 :         return 0;
     123             : }
     124             : 
     125           0 : static glfs_t *glfs_find_preopened(const char *volume, const char *connectpath)
     126             : {
     127           0 :         struct glfs_preopened *entry = NULL;
     128             : 
     129           0 :         for (entry = glfs_preopened; entry; entry = entry->next) {
     130           0 :                 if (strcmp(entry->volume, volume) == 0 &&
     131           0 :                     strcmp(entry->connectpath, connectpath) == 0)
     132             :                 {
     133           0 :                         entry->ref++;
     134           0 :                         return entry->fs;
     135             :                 }
     136             :         }
     137             : 
     138           0 :         return NULL;
     139             : }
     140             : 
     141           0 : static void glfs_clear_preopened(glfs_t *fs)
     142             : {
     143           0 :         struct glfs_preopened *entry = NULL;
     144             : 
     145           0 :         for (entry = glfs_preopened; entry; entry = entry->next) {
     146           0 :                 if (entry->fs == fs) {
     147           0 :                         if (--entry->ref)
     148           0 :                                 return;
     149             : 
     150           0 :                         DLIST_REMOVE(glfs_preopened, entry);
     151             : 
     152           0 :                         glfs_fini(entry->fs);
     153           0 :                         talloc_free(entry);
     154             :                 }
     155             :         }
     156             : }
     157             : 
     158           0 : static int vfs_gluster_set_volfile_servers(glfs_t *fs,
     159             :                                            const char *volfile_servers)
     160             : {
     161           0 :         char *server = NULL;
     162           0 :         size_t server_count = 0;
     163           0 :         size_t server_success = 0;
     164           0 :         int   ret = -1;
     165           0 :         TALLOC_CTX *frame = talloc_stackframe();
     166             : 
     167           0 :         DBG_INFO("servers list %s\n", volfile_servers);
     168             : 
     169           0 :         while (next_token_talloc(frame, &volfile_servers, &server, " \t")) {
     170           0 :                 char *transport = NULL;
     171           0 :                 char *host = NULL;
     172           0 :                 int   port = 0;
     173             : 
     174           0 :                 server_count++;
     175           0 :                 DBG_INFO("server %zu %s\n", server_count, server);
     176             : 
     177             :                 /* Determine the transport type */
     178           0 :                 if (strncmp(server, "unix+", 5) == 0) {
     179           0 :                         port = 0;
     180           0 :                         transport = talloc_strdup(frame, "unix");
     181           0 :                         if (!transport) {
     182           0 :                                 errno = ENOMEM;
     183           0 :                                 goto out;
     184             :                         }
     185           0 :                         host = talloc_strdup(frame, server + 5);
     186           0 :                         if (!host) {
     187           0 :                                 errno = ENOMEM;
     188           0 :                                 goto out;
     189             :                         }
     190             :                 } else {
     191           0 :                         char *p = NULL;
     192           0 :                         char *port_index = NULL;
     193             : 
     194           0 :                         if (strncmp(server, "tcp+", 4) == 0) {
     195           0 :                                 server += 4;
     196             :                         }
     197             : 
     198             :                         /* IPv6 is enclosed in []
     199             :                          * ':' before ']' is part of IPv6
     200             :                          * ':' after  ']' indicates port
     201             :                          */
     202           0 :                         p = server;
     203           0 :                         if (server[0] == '[') {
     204           0 :                                 server++;
     205           0 :                                 p = index(server, ']');
     206           0 :                                 if (p == NULL) {
     207             :                                         /* Malformed IPv6 */
     208           0 :                                         continue;
     209             :                                 }
     210           0 :                                 p[0] = '\0';
     211           0 :                                 p++;
     212             :                         }
     213             : 
     214           0 :                         port_index = index(p, ':');
     215             : 
     216           0 :                         if (port_index == NULL) {
     217           0 :                                 port = 0;
     218             :                         } else {
     219           0 :                                 port = atoi(port_index + 1);
     220           0 :                                 port_index[0] = '\0';
     221             :                         }
     222           0 :                         transport = talloc_strdup(frame, "tcp");
     223           0 :                         if (!transport) {
     224           0 :                                 errno = ENOMEM;
     225           0 :                                 goto out;
     226             :                         }
     227           0 :                         host = talloc_strdup(frame, server);
     228           0 :                         if (!host) {
     229           0 :                                 errno = ENOMEM;
     230           0 :                                 goto out;
     231             :                         }
     232             :                 }
     233             : 
     234           0 :                 DBG_INFO("Calling set volfile server with params "
     235             :                          "transport=%s, host=%s, port=%d\n", transport,
     236             :                           host, port);
     237             : 
     238           0 :                 ret = glfs_set_volfile_server(fs, transport, host, port);
     239           0 :                 if (ret < 0) {
     240           0 :                         DBG_WARNING("Failed to set volfile_server "
     241             :                                     "transport=%s, host=%s, port=%d (%s)\n",
     242             :                                     transport, host, port, strerror(errno));
     243             :                 } else {
     244           0 :                         server_success++;
     245             :                 }
     246             :         }
     247             : 
     248           0 : out:
     249           0 :         if (server_count == 0) {
     250           0 :                 ret = -1;
     251           0 :         } else if (server_success < server_count) {
     252           0 :                 DBG_WARNING("Failed to set %zu out of %zu servers parsed\n",
     253             :                             server_count - server_success, server_count);
     254           0 :                 ret = 0;
     255             :         }
     256             : 
     257           0 :         TALLOC_FREE(frame);
     258           0 :         return ret;
     259             : }
     260             : 
     261             : /* Disk Operations */
     262             : 
     263           0 : static int check_for_write_behind_translator(TALLOC_CTX *mem_ctx,
     264             :                                              glfs_t *fs,
     265             :                                              const char *volume)
     266             : {
     267           0 :         char *buf = NULL;
     268           0 :         char **lines = NULL;
     269           0 :         int numlines = 0;
     270             :         int i;
     271             :         char *option;
     272           0 :         bool write_behind_present = false;
     273             :         size_t newlen;
     274             :         int ret;
     275             : 
     276           0 :         ret = glfs_get_volfile(fs, NULL, 0);
     277           0 :         if (ret == 0) {
     278           0 :                 DBG_ERR("%s: Failed to get volfile for "
     279             :                         "volume (%s): No volfile\n",
     280             :                         volume,
     281             :                         strerror(errno));
     282           0 :                 return -1;
     283             :         }
     284           0 :         if (ret > 0) {
     285           0 :                 DBG_ERR("%s: Invalid return %d for glfs_get_volfile for "
     286             :                         "volume (%s): No volfile\n",
     287             :                         volume,
     288             :                         ret,
     289             :                         strerror(errno));
     290           0 :                 return -1;
     291             :         }
     292             : 
     293           0 :         newlen = 0 - ret;
     294             : 
     295           0 :         buf = talloc_zero_array(mem_ctx, char, newlen);
     296           0 :         if (buf == NULL) {
     297           0 :                 return -1;
     298             :         }
     299             : 
     300           0 :         ret = glfs_get_volfile(fs, buf, newlen);
     301           0 :         if (ret != newlen) {
     302           0 :                 TALLOC_FREE(buf);
     303           0 :                 DBG_ERR("%s: Failed to get volfile for volume (%s)\n",
     304             :                         volume, strerror(errno));
     305           0 :                 return -1;
     306             :         }
     307             : 
     308           0 :         option = talloc_asprintf(mem_ctx, "volume %s-write-behind", volume);
     309           0 :         if (option == NULL) {
     310           0 :                 TALLOC_FREE(buf);
     311           0 :                 return -1;
     312             :         }
     313             : 
     314             :         /*
     315             :          * file_lines_parse() plays horrible tricks with
     316             :          * the passed-in talloc pointers and the hierarcy
     317             :          * which makes freeing hard to get right.
     318             :          *
     319             :          * As we know mem_ctx is freed by the caller, after
     320             :          * this point don't free on exit and let the caller
     321             :          * handle it. This violates good Samba coding practice
     322             :          * but we know we're not leaking here.
     323             :          */
     324             : 
     325           0 :         lines = file_lines_parse(buf,
     326             :                                 newlen,
     327             :                                 &numlines,
     328             :                                 mem_ctx);
     329           0 :         if (lines == NULL || numlines <= 0) {
     330           0 :                 return -1;
     331             :         }
     332             :         /* On success, buf is now a talloc child of lines !! */
     333             : 
     334           0 :         for (i=0; i < numlines; i++) {
     335           0 :                 if (strequal(lines[i], option)) {
     336           0 :                         write_behind_present = true;
     337           0 :                         break;
     338             :                 }
     339             :         }
     340             : 
     341           0 :         if (write_behind_present) {
     342           0 :                 DBG_ERR("Write behind translator is enabled for "
     343             :                         "volume (%s), refusing to connect! "
     344             :                         "Please turn off the write behind translator by calling "
     345             :                         "'gluster volume set %s performance.write-behind off' "
     346             :                         "on the commandline. "
     347             :                         "Check the vfs_glusterfs(8) manpage for "
     348             :                         "further details.\n",
     349             :                         volume, volume);
     350           0 :                 return -1;
     351             :         }
     352             : 
     353           0 :         return 0;
     354             : }
     355             : 
     356           0 : static int vfs_gluster_connect(struct vfs_handle_struct *handle,
     357             :                                const char *service,
     358             :                                const char *user)
     359             : {
     360           0 :         const struct loadparm_substitution *lp_sub =
     361             :                 loadparm_s3_global_substitution();
     362             :         const char *volfile_servers;
     363             :         const char *volume;
     364             :         char *logfile;
     365             :         int loglevel;
     366           0 :         glfs_t *fs = NULL;
     367             :         TALLOC_CTX *tmp_ctx;
     368           0 :         int ret = 0;
     369           0 :         bool write_behind_pass_through_set = false;
     370             : 
     371           0 :         tmp_ctx = talloc_new(NULL);
     372           0 :         if (tmp_ctx == NULL) {
     373           0 :                 ret = -1;
     374           0 :                 goto done;
     375             :         }
     376           0 :         logfile = lp_parm_substituted_string(tmp_ctx,
     377             :                                              lp_sub,
     378           0 :                                              SNUM(handle->conn),
     379             :                                              "glusterfs",
     380             :                                              "logfile",
     381             :                                              NULL);
     382             : 
     383           0 :         loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
     384             : 
     385           0 :         volfile_servers = lp_parm_substituted_string(tmp_ctx,
     386             :                                                      lp_sub,
     387           0 :                                                      SNUM(handle->conn),
     388             :                                                      "glusterfs",
     389             :                                                      "volfile_server",
     390             :                                                      NULL);
     391           0 :         if (volfile_servers == NULL) {
     392           0 :                 volfile_servers = DEFAULT_VOLFILE_SERVER;
     393             :         }
     394             : 
     395           0 :         volume = lp_parm_const_string(SNUM(handle->conn), "glusterfs", "volume",
     396             :                                       NULL);
     397           0 :         if (volume == NULL) {
     398           0 :                 volume = service;
     399             :         }
     400             : 
     401           0 :         fs = glfs_find_preopened(volume, handle->conn->connectpath);
     402           0 :         if (fs) {
     403           0 :                 goto done;
     404             :         }
     405             : 
     406           0 :         fs = glfs_new(volume);
     407           0 :         if (fs == NULL) {
     408           0 :                 ret = -1;
     409           0 :                 goto done;
     410             :         }
     411             : 
     412           0 :         ret = vfs_gluster_set_volfile_servers(fs, volfile_servers);
     413           0 :         if (ret < 0) {
     414           0 :                 DBG_ERR("Failed to set volfile_servers from list %s\n",
     415             :                         volfile_servers);
     416           0 :                 goto done;
     417             :         }
     418             : 
     419           0 :         ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-posix-acl",
     420             :                                      "true");
     421           0 :         if (ret < 0) {
     422           0 :                 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
     423           0 :                 goto done;
     424             :         }
     425             : 
     426           0 :         ret = glfs_set_xlator_option(fs, "*-md-cache", "cache-selinux",
     427             :                                      "true");
     428           0 :         if (ret < 0) {
     429           0 :                 DEBUG(0, ("%s: Failed to set xlator options\n", volume));
     430           0 :                 goto done;
     431             :         }
     432             : 
     433           0 :         ret = glfs_set_xlator_option(fs, "*-snapview-client",
     434             :                                      "snapdir-entry-path",
     435           0 :                                      handle->conn->connectpath);
     436           0 :         if (ret < 0) {
     437           0 :                 DEBUG(0, ("%s: Failed to set xlator option:"
     438             :                           " snapdir-entry-path\n", volume));
     439           0 :                 goto done;
     440             :         }
     441             : 
     442             : #ifdef HAVE_GFAPI_VER_7_9
     443             :         ret = glfs_set_xlator_option(fs, "*-write-behind", "pass-through",
     444             :                                      "true");
     445             :         if (ret < 0) {
     446             :                 DBG_ERR("%s: Failed to set xlator option: pass-through\n",
     447             :                         volume);
     448             :                 goto done;
     449             :         }
     450             :         write_behind_pass_through_set = true;
     451             : #endif
     452             : 
     453           0 :         ret = glfs_set_logging(fs, logfile, loglevel);
     454           0 :         if (ret < 0) {
     455           0 :                 DEBUG(0, ("%s: Failed to set logfile %s loglevel %d\n",
     456             :                           volume, logfile, loglevel));
     457           0 :                 goto done;
     458             :         }
     459             : 
     460           0 :         ret = glfs_init(fs);
     461           0 :         if (ret < 0) {
     462           0 :                 DEBUG(0, ("%s: Failed to initialize volume (%s)\n",
     463             :                           volume, strerror(errno)));
     464           0 :                 goto done;
     465             :         }
     466             : 
     467           0 :         if (!write_behind_pass_through_set) {
     468           0 :                 ret = check_for_write_behind_translator(tmp_ctx, fs, volume);
     469           0 :                 if (ret < 0) {
     470           0 :                         goto done;
     471             :                 }
     472             :         }
     473             : 
     474           0 :         ret = glfs_set_preopened(volume, handle->conn->connectpath, fs);
     475           0 :         if (ret < 0) {
     476           0 :                 DEBUG(0, ("%s: Failed to register volume (%s)\n",
     477             :                           volume, strerror(errno)));
     478           0 :                 goto done;
     479             :         }
     480             : 
     481             :         /*
     482             :          * The shadow_copy2 module will fail to export subdirectories
     483             :          * of a gluster volume unless we specify the mount point,
     484             :          * because the detection fails if the file system is not
     485             :          * locally mounted:
     486             :          * https://bugzilla.samba.org/show_bug.cgi?id=13091
     487             :          */
     488           0 :         lp_do_parameter(SNUM(handle->conn), "shadow:mountpoint", "/");
     489             : 
     490             :         /*
     491             :          * Unless we have an async implementation of getxattrat turn this off.
     492             :          */
     493           0 :         lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false");
     494             : 
     495           0 : done:
     496           0 :         if (ret < 0) {
     497           0 :                 if (fs)
     498           0 :                         glfs_fini(fs);
     499             :         } else {
     500           0 :                 DBG_ERR("%s: Initialized volume from servers %s\n",
     501             :                         volume, volfile_servers);
     502           0 :                 handle->data = fs;
     503             :         }
     504           0 :         talloc_free(tmp_ctx);
     505           0 :         return ret;
     506             : }
     507             : 
     508           0 : static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)
     509             : {
     510           0 :         glfs_t *fs = NULL;
     511             : 
     512           0 :         fs = handle->data;
     513             : 
     514           0 :         glfs_clear_preopened(fs);
     515           0 : }
     516             : 
     517           0 : static uint64_t vfs_gluster_disk_free(struct vfs_handle_struct *handle,
     518             :                                 const struct smb_filename *smb_fname,
     519             :                                 uint64_t *bsize_p,
     520             :                                 uint64_t *dfree_p,
     521             :                                 uint64_t *dsize_p)
     522             : {
     523           0 :         struct statvfs statvfs = { 0, };
     524             :         int ret;
     525             : 
     526           0 :         ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
     527           0 :         if (ret < 0) {
     528           0 :                 return -1;
     529             :         }
     530             : 
     531           0 :         if (bsize_p != NULL) {
     532           0 :                 *bsize_p = (uint64_t)statvfs.f_bsize; /* Block size */
     533             :         }
     534           0 :         if (dfree_p != NULL) {
     535           0 :                 *dfree_p = (uint64_t)statvfs.f_bavail; /* Available Block units */
     536             :         }
     537           0 :         if (dsize_p != NULL) {
     538           0 :                 *dsize_p = (uint64_t)statvfs.f_blocks; /* Total Block units */
     539             :         }
     540             : 
     541           0 :         return (uint64_t)statvfs.f_bavail;
     542             : }
     543             : 
     544           0 : static int vfs_gluster_get_quota(struct vfs_handle_struct *handle,
     545             :                                 const struct smb_filename *smb_fname,
     546             :                                 enum SMB_QUOTA_TYPE qtype,
     547             :                                 unid_t id,
     548             :                                 SMB_DISK_QUOTA *qt)
     549             : {
     550           0 :         errno = ENOSYS;
     551           0 :         return -1;
     552             : }
     553             : 
     554             : static int
     555           0 : vfs_gluster_set_quota(struct vfs_handle_struct *handle,
     556             :                       enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt)
     557             : {
     558           0 :         errno = ENOSYS;
     559           0 :         return -1;
     560             : }
     561             : 
     562           0 : static int vfs_gluster_statvfs(struct vfs_handle_struct *handle,
     563             :                                 const struct smb_filename *smb_fname,
     564             :                                 struct vfs_statvfs_struct *vfs_statvfs)
     565             : {
     566           0 :         struct statvfs statvfs = { 0, };
     567             :         int ret;
     568             : 
     569           0 :         ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
     570           0 :         if (ret < 0) {
     571           0 :                 DEBUG(0, ("glfs_statvfs(%s) failed: %s\n",
     572             :                           smb_fname->base_name, strerror(errno)));
     573           0 :                 return -1;
     574             :         }
     575             : 
     576           0 :         ZERO_STRUCTP(vfs_statvfs);
     577             : 
     578           0 :         vfs_statvfs->OptimalTransferSize = statvfs.f_frsize;
     579           0 :         vfs_statvfs->BlockSize = statvfs.f_bsize;
     580           0 :         vfs_statvfs->TotalBlocks = statvfs.f_blocks;
     581           0 :         vfs_statvfs->BlocksAvail = statvfs.f_bfree;
     582           0 :         vfs_statvfs->UserBlocksAvail = statvfs.f_bavail;
     583           0 :         vfs_statvfs->TotalFileNodes = statvfs.f_files;
     584           0 :         vfs_statvfs->FreeFileNodes = statvfs.f_ffree;
     585           0 :         vfs_statvfs->FsIdentifier = statvfs.f_fsid;
     586           0 :         vfs_statvfs->FsCapabilities =
     587             :             FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
     588             : 
     589           0 :         return ret;
     590             : }
     591             : 
     592           0 : static uint32_t vfs_gluster_fs_capabilities(struct vfs_handle_struct *handle,
     593             :                                             enum timestamp_set_resolution *p_ts_res)
     594             : {
     595           0 :         uint32_t caps = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
     596             : 
     597             : #ifdef HAVE_GFAPI_VER_6
     598           0 :         caps |= FILE_SUPPORTS_SPARSE_FILES;
     599             : #endif
     600             : 
     601             : #ifdef STAT_HAVE_NSEC
     602             :         *p_ts_res = TIMESTAMP_SET_NT_OR_BETTER;
     603             : #endif
     604             : 
     605           0 :         return caps;
     606             : }
     607             : 
     608           0 : static glfs_fd_t *vfs_gluster_fetch_glfd(struct vfs_handle_struct *handle,
     609             :                                          const files_struct *fsp)
     610             : {
     611           0 :         glfs_fd_t **glfd = (glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
     612           0 :         if (glfd == NULL) {
     613           0 :                 DBG_INFO("Failed to fetch fsp extension\n");
     614           0 :                 return NULL;
     615             :         }
     616           0 :         if (*glfd == NULL) {
     617           0 :                 DBG_INFO("Empty glfs_fd_t pointer\n");
     618           0 :                 return NULL;
     619             :         }
     620             : 
     621           0 :         return *glfd;
     622             : }
     623             : 
     624           0 : static DIR *vfs_gluster_fdopendir(struct vfs_handle_struct *handle,
     625             :                                   files_struct *fsp, const char *mask,
     626             :                                   uint32_t attributes)
     627             : {
     628           0 :         glfs_fd_t *glfd = NULL;
     629             : 
     630           0 :         glfd = glfs_opendir(handle->data, fsp->fsp_name->base_name);
     631           0 :         if (glfd == NULL) {
     632           0 :                 return NULL;
     633             :         }
     634             : 
     635           0 :         return (DIR *)glfd;
     636             : }
     637             : 
     638           0 : static int vfs_gluster_closedir(struct vfs_handle_struct *handle, DIR *dirp)
     639             : {
     640             :         int ret;
     641             : 
     642           0 :         START_PROFILE(syscall_closedir);
     643           0 :         ret = glfs_closedir((void *)dirp);
     644           0 :         END_PROFILE(syscall_closedir);
     645             : 
     646           0 :         return ret;
     647             : }
     648             : 
     649           0 : static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle,
     650             :                                           struct files_struct *dirfsp,
     651             :                                           DIR *dirp,
     652             :                                           SMB_STRUCT_STAT *sbuf)
     653             : {
     654             :         static char direntbuf[512];
     655             :         int ret;
     656             :         struct stat stat;
     657           0 :         struct dirent *dirent = 0;
     658             : 
     659           0 :         START_PROFILE(syscall_readdir);
     660           0 :         if (sbuf != NULL) {
     661           0 :                 ret = glfs_readdirplus_r((void *)dirp, &stat, (void *)direntbuf,
     662             :                                          &dirent);
     663             :         } else {
     664           0 :                 ret = glfs_readdir_r((void *)dirp, (void *)direntbuf, &dirent);
     665             :         }
     666             : 
     667           0 :         if ((ret < 0) || (dirent == NULL)) {
     668           0 :                 END_PROFILE(syscall_readdir);
     669           0 :                 return NULL;
     670             :         }
     671             : 
     672           0 :         if (sbuf != NULL) {
     673           0 :                 SET_STAT_INVALID(*sbuf);
     674           0 :                 if (!S_ISLNK(stat.st_mode)) {
     675           0 :                         smb_stat_ex_from_stat(sbuf, &stat);
     676             :                 }
     677             :         }
     678             : 
     679           0 :         END_PROFILE(syscall_readdir);
     680           0 :         return dirent;
     681             : }
     682             : 
     683           0 : static long vfs_gluster_telldir(struct vfs_handle_struct *handle, DIR *dirp)
     684             : {
     685             :         long ret;
     686             : 
     687           0 :         START_PROFILE(syscall_telldir);
     688           0 :         ret = glfs_telldir((void *)dirp);
     689           0 :         END_PROFILE(syscall_telldir);
     690             : 
     691           0 :         return ret;
     692             : }
     693             : 
     694           0 : static void vfs_gluster_seekdir(struct vfs_handle_struct *handle, DIR *dirp,
     695             :                                 long offset)
     696             : {
     697           0 :         START_PROFILE(syscall_seekdir);
     698           0 :         glfs_seekdir((void *)dirp, offset);
     699           0 :         END_PROFILE(syscall_seekdir);
     700           0 : }
     701             : 
     702           0 : static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle, DIR *dirp)
     703             : {
     704           0 :         START_PROFILE(syscall_rewinddir);
     705           0 :         glfs_seekdir((void *)dirp, 0);
     706           0 :         END_PROFILE(syscall_rewinddir);
     707           0 : }
     708             : 
     709           0 : static int vfs_gluster_mkdirat(struct vfs_handle_struct *handle,
     710             :                         struct files_struct *dirfsp,
     711             :                         const struct smb_filename *smb_fname,
     712             :                         mode_t mode)
     713             : {
     714             :         int ret;
     715             : 
     716             : #ifdef HAVE_GFAPI_VER_7_11
     717             :         glfs_fd_t *pglfd = NULL;
     718             : 
     719             :         START_PROFILE(syscall_mkdirat);
     720             : 
     721             :         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
     722             :         if (pglfd == NULL) {
     723             :                 END_PROFILE(syscall_mkdirat);
     724             :                 DBG_ERR("Failed to fetch gluster fd\n");
     725             :                 return -1;
     726             :         }
     727             : 
     728             :         ret = glfs_mkdirat(pglfd, smb_fname->base_name, mode);
     729             : #else
     730           0 :         struct smb_filename *full_fname = NULL;
     731             : 
     732           0 :         START_PROFILE(syscall_mkdirat);
     733             : 
     734           0 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
     735             :                                                   dirfsp,
     736             :                                                   smb_fname);
     737           0 :         if (full_fname == NULL) {
     738           0 :                 END_PROFILE(syscall_mkdirat);
     739           0 :                 return -1;
     740             :         }
     741             : 
     742           0 :         ret = glfs_mkdir(handle->data, full_fname->base_name, mode);
     743             : 
     744           0 :         TALLOC_FREE(full_fname);
     745             : #endif
     746             : 
     747           0 :         END_PROFILE(syscall_mkdirat);
     748             : 
     749           0 :         return ret;
     750             : }
     751             : 
     752           0 : static int vfs_gluster_openat(struct vfs_handle_struct *handle,
     753             :                               const struct files_struct *dirfsp,
     754             :                               const struct smb_filename *smb_fname,
     755             :                               files_struct *fsp,
     756             :                               const struct vfs_open_how *how)
     757             : {
     758           0 :         int flags = how->flags;
     759           0 :         struct smb_filename *full_fname = NULL;
     760           0 :         bool have_opath = false;
     761           0 :         bool became_root = false;
     762             :         glfs_fd_t *glfd;
     763           0 :         glfs_fd_t *pglfd = NULL;
     764             :         glfs_fd_t **p_tmp;
     765             : 
     766           0 :         START_PROFILE(syscall_openat);
     767             : 
     768           0 :         if (how->resolve != 0) {
     769           0 :                 END_PROFILE(syscall_openat);
     770           0 :                 errno = ENOSYS;
     771           0 :                 return -1;
     772             :         }
     773             : 
     774           0 :         p_tmp = VFS_ADD_FSP_EXTENSION(handle, fsp, glfs_fd_t *, NULL);
     775           0 :         if (p_tmp == NULL) {
     776           0 :                 END_PROFILE(syscall_openat);
     777           0 :                 errno = ENOMEM;
     778           0 :                 return -1;
     779             :         }
     780             : 
     781             : #ifdef O_PATH
     782           0 :         have_opath = true;
     783           0 :         if (fsp->fsp_flags.is_pathref) {
     784           0 :                 flags |= O_PATH;
     785             :         }
     786             : #endif
     787             : 
     788           0 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
     789             :                                                   dirfsp,
     790             :                                                   smb_fname);
     791           0 :         if (full_fname == NULL) {
     792           0 :                 END_PROFILE(syscall_openat);
     793           0 :                 return -1;
     794             :         }
     795             : 
     796           0 :         if (fsp->fsp_flags.is_pathref && !have_opath) {
     797           0 :                 become_root();
     798           0 :                 became_root = true;
     799             :         }
     800             : 
     801           0 :         if (fsp_get_pathref_fd(dirfsp) != AT_FDCWD) {
     802             : #ifdef HAVE_GFAPI_VER_7_11
     803             :                 /*
     804             :                  * Fetch Gluster fd for parent directory using dirfsp
     805             :                  * before calling glfs_openat();
     806             :                  */
     807             :                 pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
     808             :                 if (pglfd == NULL) {
     809             :                         END_PROFILE(syscall_openat);
     810             :                         DBG_ERR("Failed to fetch gluster fd\n");
     811             :                         return -1;
     812             :                 }
     813             : 
     814             :                 glfd = glfs_openat(pglfd,
     815             :                                    smb_fname->base_name,
     816             :                                    flags,
     817             :                                    how->mode);
     818             : #else
     819             :                 /*
     820             :                  * Replace smb_fname with full_path constructed above.
     821             :                  */
     822           0 :                 smb_fname = full_fname;
     823             : #endif
     824             :         }
     825             : 
     826           0 :         if (pglfd == NULL) {
     827             :                 /*
     828             :                  * smb_fname can either be a full_path or the same one
     829             :                  * as received from the caller. In the latter case we
     830             :                  * are operating at current working directory.
     831             :                  */
     832           0 :                 if (flags & O_CREAT) {
     833           0 :                         glfd = glfs_creat(handle->data,
     834           0 :                                           smb_fname->base_name,
     835             :                                           flags,
     836             :                                           how->mode);
     837             :                 } else {
     838           0 :                         glfd = glfs_open(handle->data,
     839           0 :                                          smb_fname->base_name,
     840             :                                          flags);
     841             :                 }
     842             :         }
     843             : 
     844           0 :         if (became_root) {
     845           0 :                 unbecome_root();
     846             :         }
     847             : 
     848           0 :         TALLOC_FREE(full_fname);
     849             : 
     850           0 :         fsp->fsp_flags.have_proc_fds = false;
     851             : 
     852           0 :         if (glfd == NULL) {
     853           0 :                 END_PROFILE(syscall_openat);
     854             :                 /* no extension destroy_fn, so no need to save errno */
     855           0 :                 VFS_REMOVE_FSP_EXTENSION(handle, fsp);
     856           0 :                 return -1;
     857             :         }
     858             : 
     859           0 :         *p_tmp = glfd;
     860             : 
     861           0 :         END_PROFILE(syscall_openat);
     862             :         /* An arbitrary value for error reporting, so you know its us. */
     863           0 :         return 13371337;
     864             : }
     865             : 
     866           0 : static int vfs_gluster_close(struct vfs_handle_struct *handle,
     867             :                              files_struct *fsp)
     868             : {
     869             :         int ret;
     870           0 :         glfs_fd_t *glfd = NULL;
     871             : 
     872           0 :         START_PROFILE(syscall_close);
     873             : 
     874           0 :         glfd = vfs_gluster_fetch_glfd(handle, fsp);
     875           0 :         if (glfd == NULL) {
     876           0 :                 END_PROFILE(syscall_close);
     877           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
     878           0 :                 return -1;
     879             :         }
     880             : 
     881           0 :         VFS_REMOVE_FSP_EXTENSION(handle, fsp);
     882             : 
     883           0 :         ret = glfs_close(glfd);
     884           0 :         END_PROFILE(syscall_close);
     885             : 
     886           0 :         return ret;
     887             : }
     888             : 
     889           0 : static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle,
     890             :                                  files_struct *fsp, void *data, size_t n,
     891             :                                  off_t offset)
     892             : {
     893             :         ssize_t ret;
     894           0 :         glfs_fd_t *glfd = NULL;
     895             : 
     896           0 :         START_PROFILE_BYTES(syscall_pread, n);
     897             : 
     898           0 :         glfd = vfs_gluster_fetch_glfd(handle, fsp);
     899           0 :         if (glfd == NULL) {
     900           0 :                 END_PROFILE_BYTES(syscall_pread);
     901           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
     902           0 :                 return -1;
     903             :         }
     904             : 
     905             : #ifdef HAVE_GFAPI_VER_7_6
     906             :         ret = glfs_pread(glfd, data, n, offset, 0, NULL);
     907             : #else
     908           0 :         ret = glfs_pread(glfd, data, n, offset, 0);
     909             : #endif
     910           0 :         END_PROFILE_BYTES(syscall_pread);
     911             : 
     912           0 :         return ret;
     913             : }
     914             : 
     915             : struct vfs_gluster_pread_state {
     916             :         ssize_t ret;
     917             :         glfs_fd_t *fd;
     918             :         void *buf;
     919             :         size_t count;
     920             :         off_t offset;
     921             : 
     922             :         struct vfs_aio_state vfs_aio_state;
     923             :         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
     924             : };
     925             : 
     926             : static void vfs_gluster_pread_do(void *private_data);
     927             : static void vfs_gluster_pread_done(struct tevent_req *subreq);
     928             : static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state);
     929             : 
     930           0 : static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
     931             :                                                   *handle, TALLOC_CTX *mem_ctx,
     932             :                                                   struct tevent_context *ev,
     933             :                                                   files_struct *fsp,
     934             :                                                   void *data, size_t n,
     935             :                                                   off_t offset)
     936             : {
     937             :         struct vfs_gluster_pread_state *state;
     938             :         struct tevent_req *req, *subreq;
     939             : 
     940           0 :         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
     941           0 :         if (glfd == NULL) {
     942           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
     943           0 :                 return NULL;
     944             :         }
     945             : 
     946           0 :         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pread_state);
     947           0 :         if (req == NULL) {
     948           0 :                 return NULL;
     949             :         }
     950             : 
     951           0 :         state->ret = -1;
     952           0 :         state->fd = glfd;
     953           0 :         state->buf = data;
     954           0 :         state->count = n;
     955           0 :         state->offset = offset;
     956             : 
     957           0 :         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
     958             :                                      state->profile_bytes, n);
     959           0 :         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
     960             : 
     961           0 :         subreq = pthreadpool_tevent_job_send(
     962           0 :                 state, ev, handle->conn->sconn->pool,
     963             :                 vfs_gluster_pread_do, state);
     964           0 :         if (tevent_req_nomem(subreq, req)) {
     965           0 :                 return tevent_req_post(req, ev);
     966             :         }
     967           0 :         tevent_req_set_callback(subreq, vfs_gluster_pread_done, req);
     968             : 
     969           0 :         talloc_set_destructor(state, vfs_gluster_pread_state_destructor);
     970             : 
     971           0 :         return req;
     972             : }
     973             : 
     974           0 : static void vfs_gluster_pread_do(void *private_data)
     975             : {
     976           0 :         struct vfs_gluster_pread_state *state = talloc_get_type_abort(
     977             :                 private_data, struct vfs_gluster_pread_state);
     978             :         struct timespec start_time;
     979             :         struct timespec end_time;
     980             : 
     981           0 :         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
     982             : 
     983           0 :         PROFILE_TIMESTAMP(&start_time);
     984             : 
     985             :         do {
     986             : #ifdef HAVE_GFAPI_VER_7_6
     987             :                 state->ret = glfs_pread(state->fd, state->buf, state->count,
     988             :                                         state->offset, 0, NULL);
     989             : #else
     990           0 :                 state->ret = glfs_pread(state->fd, state->buf, state->count,
     991             :                                         state->offset, 0);
     992             : #endif
     993           0 :         } while ((state->ret == -1) && (errno == EINTR));
     994             : 
     995           0 :         if (state->ret == -1) {
     996           0 :                 state->vfs_aio_state.error = errno;
     997             :         }
     998             : 
     999           0 :         PROFILE_TIMESTAMP(&end_time);
    1000             : 
    1001           0 :         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
    1002             : 
    1003           0 :         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
    1004           0 : }
    1005             : 
    1006           0 : static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state)
    1007             : {
    1008           0 :         return -1;
    1009             : }
    1010             : 
    1011           0 : static void vfs_gluster_pread_done(struct tevent_req *subreq)
    1012             : {
    1013           0 :         struct tevent_req *req = tevent_req_callback_data(
    1014             :                 subreq, struct tevent_req);
    1015           0 :         struct vfs_gluster_pread_state *state = tevent_req_data(
    1016             :                 req, struct vfs_gluster_pread_state);
    1017             :         int ret;
    1018             : 
    1019           0 :         ret = pthreadpool_tevent_job_recv(subreq);
    1020           0 :         TALLOC_FREE(subreq);
    1021           0 :         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
    1022           0 :         talloc_set_destructor(state, NULL);
    1023           0 :         if (ret != 0) {
    1024           0 :                 if (ret != EAGAIN) {
    1025           0 :                         tevent_req_error(req, ret);
    1026           0 :                         return;
    1027             :                 }
    1028             :                 /*
    1029             :                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
    1030             :                  * means the lower level pthreadpool failed to create a new
    1031             :                  * thread. Fallback to sync processing in that case to allow
    1032             :                  * some progress for the client.
    1033             :                  */
    1034           0 :                 vfs_gluster_pread_do(state);
    1035             :         }
    1036             : 
    1037           0 :         tevent_req_done(req);
    1038             : }
    1039             : 
    1040           0 : static ssize_t vfs_gluster_pread_recv(struct tevent_req *req,
    1041             :                                       struct vfs_aio_state *vfs_aio_state)
    1042             : {
    1043           0 :         struct vfs_gluster_pread_state *state = tevent_req_data(
    1044             :                 req, struct vfs_gluster_pread_state);
    1045             : 
    1046           0 :         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
    1047           0 :                 return -1;
    1048             :         }
    1049             : 
    1050           0 :         *vfs_aio_state = state->vfs_aio_state;
    1051           0 :         return state->ret;
    1052             : }
    1053             : 
    1054             : struct vfs_gluster_pwrite_state {
    1055             :         ssize_t ret;
    1056             :         glfs_fd_t *fd;
    1057             :         const void *buf;
    1058             :         size_t count;
    1059             :         off_t offset;
    1060             : 
    1061             :         struct vfs_aio_state vfs_aio_state;
    1062             :         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
    1063             : };
    1064             : 
    1065             : static void vfs_gluster_pwrite_do(void *private_data);
    1066             : static void vfs_gluster_pwrite_done(struct tevent_req *subreq);
    1067             : static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state);
    1068             : 
    1069           0 : static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
    1070             :                                                   *handle, TALLOC_CTX *mem_ctx,
    1071             :                                                   struct tevent_context *ev,
    1072             :                                                   files_struct *fsp,
    1073             :                                                   const void *data, size_t n,
    1074             :                                                   off_t offset)
    1075             : {
    1076             :         struct tevent_req *req, *subreq;
    1077             :         struct vfs_gluster_pwrite_state *state;
    1078             : 
    1079           0 :         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
    1080           0 :         if (glfd == NULL) {
    1081           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    1082           0 :                 return NULL;
    1083             :         }
    1084             : 
    1085           0 :         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pwrite_state);
    1086           0 :         if (req == NULL) {
    1087           0 :                 return NULL;
    1088             :         }
    1089             : 
    1090           0 :         state->ret = -1;
    1091           0 :         state->fd = glfd;
    1092           0 :         state->buf = data;
    1093           0 :         state->count = n;
    1094           0 :         state->offset = offset;
    1095             : 
    1096           0 :         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p,
    1097             :                                      state->profile_bytes, n);
    1098           0 :         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
    1099             : 
    1100           0 :         subreq = pthreadpool_tevent_job_send(
    1101           0 :                 state, ev, handle->conn->sconn->pool,
    1102             :                 vfs_gluster_pwrite_do, state);
    1103           0 :         if (tevent_req_nomem(subreq, req)) {
    1104           0 :                 return tevent_req_post(req, ev);
    1105             :         }
    1106           0 :         tevent_req_set_callback(subreq, vfs_gluster_pwrite_done, req);
    1107             : 
    1108           0 :         talloc_set_destructor(state, vfs_gluster_pwrite_state_destructor);
    1109             : 
    1110           0 :         return req;
    1111             : }
    1112             : 
    1113           0 : static void vfs_gluster_pwrite_do(void *private_data)
    1114             : {
    1115           0 :         struct vfs_gluster_pwrite_state *state = talloc_get_type_abort(
    1116             :                 private_data, struct vfs_gluster_pwrite_state);
    1117             :         struct timespec start_time;
    1118             :         struct timespec end_time;
    1119             : 
    1120           0 :         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
    1121             : 
    1122           0 :         PROFILE_TIMESTAMP(&start_time);
    1123             : 
    1124             :         do {
    1125             : #ifdef HAVE_GFAPI_VER_7_6
    1126             :                 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
    1127             :                                          state->offset, 0, NULL, NULL);
    1128             : #else
    1129           0 :                 state->ret = glfs_pwrite(state->fd, state->buf, state->count,
    1130             :                                          state->offset, 0);
    1131             : #endif
    1132           0 :         } while ((state->ret == -1) && (errno == EINTR));
    1133             : 
    1134           0 :         if (state->ret == -1) {
    1135           0 :                 state->vfs_aio_state.error = errno;
    1136             :         }
    1137             : 
    1138           0 :         PROFILE_TIMESTAMP(&end_time);
    1139             : 
    1140           0 :         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
    1141             : 
    1142           0 :         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
    1143           0 : }
    1144             : 
    1145           0 : static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state)
    1146             : {
    1147           0 :         return -1;
    1148             : }
    1149             : 
    1150           0 : static void vfs_gluster_pwrite_done(struct tevent_req *subreq)
    1151             : {
    1152           0 :         struct tevent_req *req = tevent_req_callback_data(
    1153             :                 subreq, struct tevent_req);
    1154           0 :         struct vfs_gluster_pwrite_state *state = tevent_req_data(
    1155             :                 req, struct vfs_gluster_pwrite_state);
    1156             :         int ret;
    1157             : 
    1158           0 :         ret = pthreadpool_tevent_job_recv(subreq);
    1159           0 :         TALLOC_FREE(subreq);
    1160           0 :         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
    1161           0 :         talloc_set_destructor(state, NULL);
    1162           0 :         if (ret != 0) {
    1163           0 :                 if (ret != EAGAIN) {
    1164           0 :                         tevent_req_error(req, ret);
    1165           0 :                         return;
    1166             :                 }
    1167             :                 /*
    1168             :                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
    1169             :                  * means the lower level pthreadpool failed to create a new
    1170             :                  * thread. Fallback to sync processing in that case to allow
    1171             :                  * some progress for the client.
    1172             :                  */
    1173           0 :                 vfs_gluster_pwrite_do(state);
    1174             :         }
    1175             : 
    1176           0 :         tevent_req_done(req);
    1177             : }
    1178             : 
    1179           0 : static ssize_t vfs_gluster_pwrite_recv(struct tevent_req *req,
    1180             :                                        struct vfs_aio_state *vfs_aio_state)
    1181             : {
    1182           0 :         struct vfs_gluster_pwrite_state *state = tevent_req_data(
    1183             :                 req, struct vfs_gluster_pwrite_state);
    1184             : 
    1185           0 :         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
    1186           0 :                 return -1;
    1187             :         }
    1188             : 
    1189           0 :         *vfs_aio_state = state->vfs_aio_state;
    1190             : 
    1191           0 :         return state->ret;
    1192             : }
    1193             : 
    1194           0 : static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
    1195             :                                   files_struct *fsp, const void *data,
    1196             :                                   size_t n, off_t offset)
    1197             : {
    1198             :         ssize_t ret;
    1199           0 :         glfs_fd_t *glfd = NULL;
    1200             : 
    1201           0 :         START_PROFILE_BYTES(syscall_pwrite, n);
    1202             : 
    1203           0 :         glfd = vfs_gluster_fetch_glfd(handle, fsp);
    1204           0 :         if (glfd == NULL) {
    1205           0 :                 END_PROFILE_BYTES(syscall_pwrite);
    1206           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    1207           0 :                 return -1;
    1208             :         }
    1209             : 
    1210             : #ifdef HAVE_GFAPI_VER_7_6
    1211             :         ret = glfs_pwrite(glfd, data, n, offset, 0, NULL, NULL);
    1212             : #else
    1213           0 :         ret = glfs_pwrite(glfd, data, n, offset, 0);
    1214             : #endif
    1215           0 :         END_PROFILE_BYTES(syscall_pwrite);
    1216             : 
    1217           0 :         return ret;
    1218             : }
    1219             : 
    1220           0 : static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
    1221             :                                files_struct *fsp, off_t offset, int whence)
    1222             : {
    1223           0 :         off_t ret = 0;
    1224           0 :         glfs_fd_t *glfd = NULL;
    1225             : 
    1226           0 :         START_PROFILE(syscall_lseek);
    1227             : 
    1228           0 :         glfd = vfs_gluster_fetch_glfd(handle, fsp);
    1229           0 :         if (glfd == NULL) {
    1230           0 :                 END_PROFILE(syscall_lseek);
    1231           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    1232           0 :                 return -1;
    1233             :         }
    1234             : 
    1235           0 :         ret = glfs_lseek(glfd, offset, whence);
    1236           0 :         END_PROFILE(syscall_lseek);
    1237             : 
    1238           0 :         return ret;
    1239             : }
    1240             : 
    1241           0 : static ssize_t vfs_gluster_sendfile(struct vfs_handle_struct *handle, int tofd,
    1242             :                                     files_struct *fromfsp,
    1243             :                                     const DATA_BLOB *hdr,
    1244             :                                     off_t offset, size_t n)
    1245             : {
    1246           0 :         errno = ENOTSUP;
    1247           0 :         return -1;
    1248             : }
    1249             : 
    1250           0 : static ssize_t vfs_gluster_recvfile(struct vfs_handle_struct *handle,
    1251             :                                     int fromfd, files_struct *tofsp,
    1252             :                                     off_t offset, size_t n)
    1253             : {
    1254           0 :         errno = ENOTSUP;
    1255           0 :         return -1;
    1256             : }
    1257             : 
    1258           0 : static int vfs_gluster_renameat(struct vfs_handle_struct *handle,
    1259             :                         files_struct *srcfsp,
    1260             :                         const struct smb_filename *smb_fname_src,
    1261             :                         files_struct *dstfsp,
    1262             :                         const struct smb_filename *smb_fname_dst)
    1263             : {
    1264             :         int ret;
    1265             : 
    1266             : #ifdef HAVE_GFAPI_VER_7_11
    1267             :         glfs_fd_t *src_pglfd = NULL;
    1268             :         glfs_fd_t *dst_pglfd = NULL;
    1269             : 
    1270             :         START_PROFILE(syscall_renameat);
    1271             : 
    1272             :         src_pglfd = vfs_gluster_fetch_glfd(handle, srcfsp);
    1273             :         if (src_pglfd == NULL) {
    1274             :                 END_PROFILE(syscall_renameat);
    1275             :                 DBG_ERR("Failed to fetch gluster fd\n");
    1276             :                 return -1;
    1277             :         }
    1278             : 
    1279             :         dst_pglfd = vfs_gluster_fetch_glfd(handle, dstfsp);
    1280             :         if (dst_pglfd == NULL) {
    1281             :                 END_PROFILE(syscall_renameat);
    1282             :                 DBG_ERR("Failed to fetch gluster fd\n");
    1283             :                 return -1;
    1284             :         }
    1285             : 
    1286             :         ret = glfs_renameat(src_pglfd, smb_fname_src->base_name,
    1287             :                             dst_pglfd, smb_fname_dst->base_name);
    1288             : #else
    1289           0 :         struct smb_filename *full_fname_src = NULL;
    1290           0 :         struct smb_filename *full_fname_dst = NULL;
    1291             : 
    1292           0 :         START_PROFILE(syscall_renameat);
    1293             : 
    1294           0 :         full_fname_src = full_path_from_dirfsp_atname(talloc_tos(),
    1295             :                                                       srcfsp,
    1296             :                                                       smb_fname_src);
    1297           0 :         if (full_fname_src == NULL) {
    1298           0 :                 END_PROFILE(syscall_renameat);
    1299           0 :                 errno = ENOMEM;
    1300           0 :                 return -1;
    1301             :         }
    1302             : 
    1303           0 :         full_fname_dst = full_path_from_dirfsp_atname(talloc_tos(),
    1304             :                                                       dstfsp,
    1305             :                                                       smb_fname_dst);
    1306           0 :         if (full_fname_dst == NULL) {
    1307           0 :                 END_PROFILE(syscall_renameat);
    1308           0 :                 TALLOC_FREE(full_fname_src);
    1309           0 :                 errno = ENOMEM;
    1310           0 :                 return -1;
    1311             :         }
    1312           0 :         ret = glfs_rename(handle->data,
    1313           0 :                           full_fname_src->base_name,
    1314           0 :                           full_fname_dst->base_name);
    1315             : 
    1316           0 :         TALLOC_FREE(full_fname_src);
    1317           0 :         TALLOC_FREE(full_fname_dst);
    1318             : #endif
    1319             : 
    1320           0 :         END_PROFILE(syscall_renameat);
    1321             : 
    1322           0 :         return ret;
    1323             : }
    1324             : 
    1325             : struct vfs_gluster_fsync_state {
    1326             :         ssize_t ret;
    1327             :         glfs_fd_t *fd;
    1328             : 
    1329             :         struct vfs_aio_state vfs_aio_state;
    1330             :         SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes);
    1331             : };
    1332             : 
    1333             : static void vfs_gluster_fsync_do(void *private_data);
    1334             : static void vfs_gluster_fsync_done(struct tevent_req *subreq);
    1335             : static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state);
    1336             : 
    1337           0 : static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct
    1338             :                                                  *handle, TALLOC_CTX *mem_ctx,
    1339             :                                                  struct tevent_context *ev,
    1340             :                                                  files_struct *fsp)
    1341             : {
    1342             :         struct tevent_req *req, *subreq;
    1343             :         struct vfs_gluster_fsync_state *state;
    1344             : 
    1345           0 :         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
    1346           0 :         if (glfd == NULL) {
    1347           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    1348           0 :                 return NULL;
    1349             :         }
    1350             : 
    1351           0 :         req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_fsync_state);
    1352           0 :         if (req == NULL) {
    1353           0 :                 return NULL;
    1354             :         }
    1355             : 
    1356           0 :         state->ret = -1;
    1357           0 :         state->fd = glfd;
    1358             : 
    1359           0 :         SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
    1360             :                                      state->profile_bytes, 0);
    1361           0 :         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
    1362             : 
    1363           0 :         subreq = pthreadpool_tevent_job_send(
    1364           0 :                 state, ev, handle->conn->sconn->pool, vfs_gluster_fsync_do, state);
    1365           0 :         if (tevent_req_nomem(subreq, req)) {
    1366           0 :                 return tevent_req_post(req, ev);
    1367             :         }
    1368           0 :         tevent_req_set_callback(subreq, vfs_gluster_fsync_done, req);
    1369             : 
    1370           0 :         talloc_set_destructor(state, vfs_gluster_fsync_state_destructor);
    1371             : 
    1372           0 :         return req;
    1373             : }
    1374             : 
    1375           0 : static void vfs_gluster_fsync_do(void *private_data)
    1376             : {
    1377           0 :         struct vfs_gluster_fsync_state *state = talloc_get_type_abort(
    1378             :                 private_data, struct vfs_gluster_fsync_state);
    1379             :         struct timespec start_time;
    1380             :         struct timespec end_time;
    1381             : 
    1382           0 :         SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
    1383             : 
    1384           0 :         PROFILE_TIMESTAMP(&start_time);
    1385             : 
    1386             :         do {
    1387             : #ifdef HAVE_GFAPI_VER_7_6
    1388             :                 state->ret = glfs_fsync(state->fd, NULL, NULL);
    1389             : #else
    1390           0 :                 state->ret = glfs_fsync(state->fd);
    1391             : #endif
    1392           0 :         } while ((state->ret == -1) && (errno == EINTR));
    1393             : 
    1394           0 :         if (state->ret == -1) {
    1395           0 :                 state->vfs_aio_state.error = errno;
    1396             :         }
    1397             : 
    1398           0 :         PROFILE_TIMESTAMP(&end_time);
    1399             : 
    1400           0 :         state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time);
    1401             : 
    1402           0 :         SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes);
    1403           0 : }
    1404             : 
    1405           0 : static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state)
    1406             : {
    1407           0 :         return -1;
    1408             : }
    1409             : 
    1410           0 : static void vfs_gluster_fsync_done(struct tevent_req *subreq)
    1411             : {
    1412           0 :         struct tevent_req *req = tevent_req_callback_data(
    1413             :                 subreq, struct tevent_req);
    1414           0 :         struct vfs_gluster_fsync_state *state = tevent_req_data(
    1415             :                 req, struct vfs_gluster_fsync_state);
    1416             :         int ret;
    1417             : 
    1418           0 :         ret = pthreadpool_tevent_job_recv(subreq);
    1419           0 :         TALLOC_FREE(subreq);
    1420           0 :         SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes);
    1421           0 :         talloc_set_destructor(state, NULL);
    1422           0 :         if (ret != 0) {
    1423           0 :                 if (ret != EAGAIN) {
    1424           0 :                         tevent_req_error(req, ret);
    1425           0 :                         return;
    1426             :                 }
    1427             :                 /*
    1428             :                  * If we get EAGAIN from pthreadpool_tevent_job_recv() this
    1429             :                  * means the lower level pthreadpool failed to create a new
    1430             :                  * thread. Fallback to sync processing in that case to allow
    1431             :                  * some progress for the client.
    1432             :                  */
    1433           0 :                 vfs_gluster_fsync_do(state);
    1434             :         }
    1435             : 
    1436           0 :         tevent_req_done(req);
    1437             : }
    1438             : 
    1439           0 : static int vfs_gluster_fsync_recv(struct tevent_req *req,
    1440             :                                   struct vfs_aio_state *vfs_aio_state)
    1441             : {
    1442           0 :         struct vfs_gluster_fsync_state *state = tevent_req_data(
    1443             :                 req, struct vfs_gluster_fsync_state);
    1444             : 
    1445           0 :         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
    1446           0 :                 return -1;
    1447             :         }
    1448             : 
    1449           0 :         *vfs_aio_state = state->vfs_aio_state;
    1450           0 :         return state->ret;
    1451             : }
    1452             : 
    1453           0 : static int vfs_gluster_stat(struct vfs_handle_struct *handle,
    1454             :                             struct smb_filename *smb_fname)
    1455             : {
    1456             :         struct stat st;
    1457             :         int ret;
    1458             : 
    1459           0 :         START_PROFILE(syscall_stat);
    1460           0 :         ret = glfs_stat(handle->data, smb_fname->base_name, &st);
    1461           0 :         if (ret == 0) {
    1462           0 :                 smb_stat_ex_from_stat(&smb_fname->st, &st);
    1463             :         }
    1464           0 :         if (ret < 0 && errno != ENOENT) {
    1465           0 :                 DEBUG(0, ("glfs_stat(%s) failed: %s\n",
    1466             :                           smb_fname->base_name, strerror(errno)));
    1467             :         }
    1468           0 :         END_PROFILE(syscall_stat);
    1469             : 
    1470           0 :         return ret;
    1471             : }
    1472             : 
    1473           0 : static int vfs_gluster_fstat(struct vfs_handle_struct *handle,
    1474             :                              files_struct *fsp, SMB_STRUCT_STAT *sbuf)
    1475             : {
    1476             :         struct stat st;
    1477             :         int ret;
    1478           0 :         glfs_fd_t *glfd = NULL;
    1479             : 
    1480           0 :         START_PROFILE(syscall_fstat);
    1481             : 
    1482           0 :         glfd = vfs_gluster_fetch_glfd(handle, fsp);
    1483           0 :         if (glfd == NULL) {
    1484           0 :                 END_PROFILE(syscall_fstat);
    1485           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    1486           0 :                 return -1;
    1487             :         }
    1488             : 
    1489           0 :         ret = glfs_fstat(glfd, &st);
    1490           0 :         if (ret == 0) {
    1491           0 :                 smb_stat_ex_from_stat(sbuf, &st);
    1492             :         }
    1493           0 :         if (ret < 0) {
    1494           0 :                 DEBUG(0, ("glfs_fstat(%d) failed: %s\n",
    1495             :                           fsp_get_io_fd(fsp), strerror(errno)));
    1496             :         }
    1497           0 :         END_PROFILE(syscall_fstat);
    1498             : 
    1499           0 :         return ret;
    1500             : }
    1501             : 
    1502           0 : static int vfs_gluster_fstatat(struct vfs_handle_struct *handle,
    1503             :                                const struct files_struct *dirfsp,
    1504             :                                const struct smb_filename *smb_fname,
    1505             :                                SMB_STRUCT_STAT *sbuf,
    1506             :                                int flags)
    1507             : {
    1508             :         struct stat st;
    1509             :         int ret;
    1510             : 
    1511             : #ifdef HAVE_GFAPI_VER_7_11
    1512             :         glfs_fd_t *pglfd = NULL;
    1513             : 
    1514             :         START_PROFILE(syscall_fstatat);
    1515             : 
    1516             :         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
    1517             :         if (pglfd == NULL) {
    1518             :                 END_PROFILE(syscall_fstatat);
    1519             :                 DBG_ERR("Failed to fetch gluster fd\n");
    1520             :                 return -1;
    1521             :         }
    1522             : 
    1523             :         ret = glfs_fstatat(pglfd, smb_fname->base_name, &st, flags);
    1524             : #else
    1525           0 :         struct smb_filename *full_fname = NULL;
    1526             : 
    1527           0 :         START_PROFILE(syscall_fstatat);
    1528             : 
    1529           0 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
    1530             :                                                   dirfsp,
    1531             :                                                   smb_fname);
    1532           0 :         if (full_fname == NULL) {
    1533           0 :                 END_PROFILE(syscall_fstatat);
    1534           0 :                 return -1;
    1535             :         }
    1536             : 
    1537           0 :         ret = glfs_stat(handle->data, full_fname->base_name, &st);
    1538             : 
    1539           0 :         TALLOC_FREE(full_fname->base_name);
    1540             : #endif
    1541             : 
    1542           0 :         if (ret == 0) {
    1543           0 :                 smb_stat_ex_from_stat(sbuf, &st);
    1544             :         }
    1545             : 
    1546           0 :         END_PROFILE(syscall_fstatat);
    1547             : 
    1548           0 :         return ret;
    1549             : }
    1550             : 
    1551           0 : static int vfs_gluster_lstat(struct vfs_handle_struct *handle,
    1552             :                              struct smb_filename *smb_fname)
    1553             : {
    1554             :         struct stat st;
    1555             :         int ret;
    1556             : 
    1557           0 :         START_PROFILE(syscall_lstat);
    1558           0 :         ret = glfs_lstat(handle->data, smb_fname->base_name, &st);
    1559           0 :         if (ret == 0) {
    1560           0 :                 smb_stat_ex_from_stat(&smb_fname->st, &st);
    1561             :         }
    1562           0 :         if (ret < 0 && errno != ENOENT) {
    1563           0 :                 DEBUG(0, ("glfs_lstat(%s) failed: %s\n",
    1564             :                           smb_fname->base_name, strerror(errno)));
    1565             :         }
    1566           0 :         END_PROFILE(syscall_lstat);
    1567             : 
    1568           0 :         return ret;
    1569             : }
    1570             : 
    1571           0 : static uint64_t vfs_gluster_get_alloc_size(struct vfs_handle_struct *handle,
    1572             :                                            files_struct *fsp,
    1573             :                                            const SMB_STRUCT_STAT *sbuf)
    1574             : {
    1575             :         uint64_t ret;
    1576             : 
    1577           0 :         START_PROFILE(syscall_get_alloc_size);
    1578           0 :         ret = sbuf->st_ex_blocks * 512;
    1579           0 :         END_PROFILE(syscall_get_alloc_size);
    1580             : 
    1581           0 :         return ret;
    1582             : }
    1583             : 
    1584           0 : static int vfs_gluster_unlinkat(struct vfs_handle_struct *handle,
    1585             :                         struct files_struct *dirfsp,
    1586             :                         const struct smb_filename *smb_fname,
    1587             :                         int flags)
    1588             : {
    1589             :         int ret;
    1590             : 
    1591             : #ifdef HAVE_GFAPI_VER_7_11
    1592             :         glfs_fd_t *pglfd = NULL;
    1593             : 
    1594             :         START_PROFILE(syscall_unlinkat);
    1595             : 
    1596             :         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
    1597             :         if (pglfd == NULL) {
    1598             :                 END_PROFILE(syscall_unlinkat);
    1599             :                 DBG_ERR("Failed to fetch gluster fd\n");
    1600             :                 return -1;
    1601             :         }
    1602             : 
    1603             :         ret = glfs_unlinkat(pglfd, smb_fname->base_name, flags);
    1604             : #else
    1605           0 :         struct smb_filename *full_fname = NULL;
    1606             : 
    1607           0 :         START_PROFILE(syscall_unlinkat);
    1608             : 
    1609           0 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
    1610             :                                                   dirfsp,
    1611             :                                                   smb_fname);
    1612           0 :         if (full_fname == NULL) {
    1613           0 :                 END_PROFILE(syscall_unlinkat);
    1614           0 :                 return -1;
    1615             :         }
    1616             : 
    1617           0 :         if (flags & AT_REMOVEDIR) {
    1618           0 :                 ret = glfs_rmdir(handle->data, full_fname->base_name);
    1619             :         } else {
    1620           0 :                 ret = glfs_unlink(handle->data, full_fname->base_name);
    1621             :         }
    1622             : 
    1623           0 :         TALLOC_FREE(full_fname);
    1624             : #endif
    1625             : 
    1626           0 :         END_PROFILE(syscall_unlinkat);
    1627             : 
    1628           0 :         return ret;
    1629             : }
    1630             : 
    1631           0 : static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
    1632             :                               files_struct *fsp, mode_t mode)
    1633             : {
    1634             :         int ret;
    1635           0 :         glfs_fd_t *glfd = NULL;
    1636             : 
    1637           0 :         START_PROFILE(syscall_fchmod);
    1638             : 
    1639           0 :         glfd = vfs_gluster_fetch_glfd(handle, fsp);
    1640           0 :         if (glfd == NULL) {
    1641           0 :                 END_PROFILE(syscall_fchmod);
    1642           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    1643           0 :                 return -1;
    1644             :         }
    1645             : 
    1646           0 :         if (!fsp->fsp_flags.is_pathref) {
    1647             :                 /*
    1648             :                  * We can use an io_fd to remove xattrs.
    1649             :                  */
    1650           0 :                 ret = glfs_fchmod(glfd, mode);
    1651             :         } else {
    1652             :                 /*
    1653             :                  * This is no longer a handle based call.
    1654             :                  */
    1655           0 :                 ret = glfs_chmod(handle->data, fsp->fsp_name->base_name, mode);
    1656             :         }
    1657           0 :         END_PROFILE(syscall_fchmod);
    1658             : 
    1659           0 :         return ret;
    1660             : }
    1661             : 
    1662           0 : static int vfs_gluster_fchown(struct vfs_handle_struct *handle,
    1663             :                               files_struct *fsp, uid_t uid, gid_t gid)
    1664             : {
    1665             :         int ret;
    1666           0 :         glfs_fd_t *glfd = NULL;
    1667             : 
    1668           0 :         START_PROFILE(syscall_fchown);
    1669             : 
    1670           0 :         glfd = vfs_gluster_fetch_glfd(handle, fsp);
    1671           0 :         if (glfd == NULL) {
    1672           0 :                 END_PROFILE(syscall_fchown);
    1673           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    1674           0 :                 return -1;
    1675             :         }
    1676             : 
    1677           0 :         ret = glfs_fchown(glfd, uid, gid);
    1678           0 :         END_PROFILE(syscall_fchown);
    1679             : 
    1680           0 :         return ret;
    1681             : }
    1682             : 
    1683           0 : static int vfs_gluster_lchown(struct vfs_handle_struct *handle,
    1684             :                         const struct smb_filename *smb_fname,
    1685             :                         uid_t uid,
    1686             :                         gid_t gid)
    1687             : {
    1688             :         int ret;
    1689             : 
    1690           0 :         START_PROFILE(syscall_lchown);
    1691           0 :         ret = glfs_lchown(handle->data, smb_fname->base_name, uid, gid);
    1692           0 :         END_PROFILE(syscall_lchown);
    1693             : 
    1694           0 :         return ret;
    1695             : }
    1696             : 
    1697           0 : static int vfs_gluster_chdir(struct vfs_handle_struct *handle,
    1698             :                         const struct smb_filename *smb_fname)
    1699             : {
    1700             :         int ret;
    1701             : 
    1702           0 :         START_PROFILE(syscall_chdir);
    1703           0 :         ret = glfs_chdir(handle->data, smb_fname->base_name);
    1704           0 :         END_PROFILE(syscall_chdir);
    1705             : 
    1706           0 :         return ret;
    1707             : }
    1708             : 
    1709           0 : static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle,
    1710             :                                 TALLOC_CTX *ctx)
    1711             : {
    1712           0 :         char cwd[PATH_MAX] = { '\0' };
    1713             :         char *ret;
    1714           0 :         struct smb_filename *smb_fname = NULL;
    1715             : 
    1716           0 :         START_PROFILE(syscall_getwd);
    1717             : 
    1718           0 :         ret = glfs_getcwd(handle->data, cwd, PATH_MAX - 1);
    1719           0 :         END_PROFILE(syscall_getwd);
    1720             : 
    1721           0 :         if (ret == NULL) {
    1722           0 :                 return NULL;
    1723             :         }
    1724           0 :         smb_fname = synthetic_smb_fname(ctx,
    1725             :                                         ret,
    1726             :                                         NULL,
    1727             :                                         NULL,
    1728             :                                         0,
    1729             :                                         0);
    1730           0 :         return smb_fname;
    1731             : }
    1732             : 
    1733           0 : static int vfs_gluster_fntimes(struct vfs_handle_struct *handle,
    1734             :                                files_struct *fsp,
    1735             :                                struct smb_file_time *ft)
    1736             : {
    1737           0 :         int ret = -1;
    1738             :         struct timespec times[2];
    1739           0 :         glfs_fd_t *glfd = NULL;
    1740             : 
    1741           0 :         START_PROFILE(syscall_fntimes);
    1742             : 
    1743           0 :         if (is_omit_timespec(&ft->atime)) {
    1744           0 :                 times[0].tv_sec = fsp->fsp_name->st.st_ex_atime.tv_sec;
    1745           0 :                 times[0].tv_nsec = fsp->fsp_name->st.st_ex_atime.tv_nsec;
    1746             :         } else {
    1747           0 :                 times[0].tv_sec = ft->atime.tv_sec;
    1748           0 :                 times[0].tv_nsec = ft->atime.tv_nsec;
    1749             :         }
    1750             : 
    1751           0 :         if (is_omit_timespec(&ft->mtime)) {
    1752           0 :                 times[1].tv_sec = fsp->fsp_name->st.st_ex_mtime.tv_sec;
    1753           0 :                 times[1].tv_nsec = fsp->fsp_name->st.st_ex_mtime.tv_nsec;
    1754             :         } else {
    1755           0 :                 times[1].tv_sec = ft->mtime.tv_sec;
    1756           0 :                 times[1].tv_nsec = ft->mtime.tv_nsec;
    1757             :         }
    1758             : 
    1759           0 :         if ((timespec_compare(&times[0],
    1760           0 :                               &fsp->fsp_name->st.st_ex_atime) == 0) &&
    1761           0 :             (timespec_compare(&times[1],
    1762           0 :                               &fsp->fsp_name->st.st_ex_mtime) == 0)) {
    1763           0 :                 END_PROFILE(syscall_fntimes);
    1764           0 :                 return 0;
    1765             :         }
    1766             : 
    1767           0 :         glfd = vfs_gluster_fetch_glfd(handle, fsp);
    1768           0 :         if (glfd == NULL) {
    1769           0 :                 END_PROFILE(syscall_fntimes);
    1770           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    1771           0 :                 return -1;
    1772             :         }
    1773             : 
    1774           0 :         if (!fsp->fsp_flags.is_pathref) {
    1775           0 :                 ret = glfs_futimens(glfd, times);
    1776             :         } else {
    1777           0 :                 ret = glfs_utimens(handle->data,
    1778           0 :                                    fsp->fsp_name->base_name,
    1779             :                                    times);
    1780             :         }
    1781           0 :         END_PROFILE(syscall_fntimes);
    1782             : 
    1783           0 :         return ret;
    1784             : }
    1785             : 
    1786           0 : static int vfs_gluster_ftruncate(struct vfs_handle_struct *handle,
    1787             :                                  files_struct *fsp, off_t offset)
    1788             : {
    1789             :         int ret;
    1790           0 :         glfs_fd_t *glfd = NULL;
    1791             : 
    1792           0 :         START_PROFILE(syscall_ftruncate);
    1793             : 
    1794           0 :         glfd = vfs_gluster_fetch_glfd(handle, fsp);
    1795           0 :         if (glfd == NULL) {
    1796           0 :                 END_PROFILE(syscall_ftruncate);
    1797           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    1798           0 :                 return -1;
    1799             :         }
    1800             : 
    1801             : #ifdef HAVE_GFAPI_VER_7_6
    1802             :         ret = glfs_ftruncate(glfd, offset, NULL, NULL);
    1803             : #else
    1804           0 :         ret = glfs_ftruncate(glfd, offset);
    1805             : #endif
    1806           0 :         END_PROFILE(syscall_ftruncate);
    1807             : 
    1808           0 :         return ret;
    1809             : }
    1810             : 
    1811           0 : static int vfs_gluster_fallocate(struct vfs_handle_struct *handle,
    1812             :                                  struct files_struct *fsp,
    1813             :                                  uint32_t mode,
    1814             :                                  off_t offset, off_t len)
    1815             : {
    1816             :         int ret;
    1817             : #ifdef HAVE_GFAPI_VER_6
    1818           0 :         glfs_fd_t *glfd = NULL;
    1819             :         int keep_size, punch_hole;
    1820             : 
    1821           0 :         START_PROFILE(syscall_fallocate);
    1822             : 
    1823           0 :         glfd = vfs_gluster_fetch_glfd(handle, fsp);
    1824           0 :         if (glfd == NULL) {
    1825           0 :                 END_PROFILE(syscall_fallocate);
    1826           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    1827           0 :                 return -1;
    1828             :         }
    1829             : 
    1830           0 :         keep_size = mode & VFS_FALLOCATE_FL_KEEP_SIZE;
    1831           0 :         punch_hole = mode & VFS_FALLOCATE_FL_PUNCH_HOLE;
    1832             : 
    1833           0 :         mode &= ~(VFS_FALLOCATE_FL_KEEP_SIZE|VFS_FALLOCATE_FL_PUNCH_HOLE);
    1834           0 :         if (mode != 0) {
    1835           0 :                 END_PROFILE(syscall_fallocate);
    1836           0 :                 errno = ENOTSUP;
    1837           0 :                 return -1;
    1838             :         }
    1839             : 
    1840           0 :         if (punch_hole) {
    1841           0 :                 ret = glfs_discard(glfd, offset, len);
    1842           0 :                 if (ret != 0) {
    1843           0 :                         DBG_DEBUG("glfs_discard failed: %s\n",
    1844             :                                   strerror(errno));
    1845             :                 }
    1846             :         }
    1847             : 
    1848           0 :         ret = glfs_fallocate(glfd, keep_size, offset, len);
    1849           0 :         END_PROFILE(syscall_fallocate);
    1850             : #else
    1851             :         errno = ENOTSUP;
    1852             :         ret = -1;
    1853             : #endif
    1854           0 :         return ret;
    1855             : }
    1856             : 
    1857           0 : static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handle,
    1858             :                                 TALLOC_CTX *ctx,
    1859             :                                 const struct smb_filename *smb_fname)
    1860             : {
    1861           0 :         char *result = NULL;
    1862           0 :         struct smb_filename *result_fname = NULL;
    1863           0 :         char *resolved_path = NULL;
    1864             : 
    1865           0 :         START_PROFILE(syscall_realpath);
    1866             : 
    1867           0 :         resolved_path = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
    1868           0 :         if (resolved_path == NULL) {
    1869           0 :                 END_PROFILE(syscall_realpath);
    1870           0 :                 errno = ENOMEM;
    1871           0 :                 return NULL;
    1872             :         }
    1873             : 
    1874           0 :         result = glfs_realpath(handle->data,
    1875           0 :                         smb_fname->base_name,
    1876             :                         resolved_path);
    1877           0 :         if (result != NULL) {
    1878           0 :                 result_fname = synthetic_smb_fname(ctx,
    1879             :                                                    result,
    1880             :                                                    NULL,
    1881             :                                                    NULL,
    1882             :                                                    0,
    1883             :                                                    0);
    1884             :         }
    1885             : 
    1886           0 :         SAFE_FREE(resolved_path);
    1887           0 :         END_PROFILE(syscall_realpath);
    1888             : 
    1889           0 :         return result_fname;
    1890             : }
    1891             : 
    1892           0 : static bool vfs_gluster_lock(struct vfs_handle_struct *handle,
    1893             :                              files_struct *fsp, int op, off_t offset,
    1894             :                              off_t count, int type)
    1895             : {
    1896           0 :         struct flock flock = { 0, };
    1897             :         int ret;
    1898           0 :         glfs_fd_t *glfd = NULL;
    1899           0 :         bool ok = false;
    1900             : 
    1901           0 :         START_PROFILE(syscall_fcntl_lock);
    1902             : 
    1903           0 :         glfd = vfs_gluster_fetch_glfd(handle, fsp);
    1904           0 :         if (glfd == NULL) {
    1905           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    1906           0 :                 ok = false;
    1907           0 :                 goto out;
    1908             :         }
    1909             : 
    1910           0 :         flock.l_type = type;
    1911           0 :         flock.l_whence = SEEK_SET;
    1912           0 :         flock.l_start = offset;
    1913           0 :         flock.l_len = count;
    1914           0 :         flock.l_pid = 0;
    1915             : 
    1916           0 :         ret = glfs_posix_lock(glfd, op, &flock);
    1917             : 
    1918           0 :         if (op == F_GETLK) {
    1919             :                 /* lock query, true if someone else has locked */
    1920           0 :                 if ((ret != -1) &&
    1921           0 :                     (flock.l_type != F_UNLCK) &&
    1922           0 :                     (flock.l_pid != 0) && (flock.l_pid != getpid())) {
    1923           0 :                         ok = true;
    1924           0 :                         goto out;
    1925             :                 }
    1926             :                 /* not me */
    1927           0 :                 ok = false;
    1928           0 :                 goto out;
    1929             :         }
    1930             : 
    1931           0 :         if (ret == -1) {
    1932           0 :                 ok = false;
    1933           0 :                 goto out;
    1934             :         }
    1935             : 
    1936           0 :         ok = true;
    1937           0 : out:
    1938           0 :         END_PROFILE(syscall_fcntl_lock);
    1939             : 
    1940           0 :         return ok;
    1941             : }
    1942             : 
    1943           0 : static int vfs_gluster_filesystem_sharemode(struct vfs_handle_struct *handle,
    1944             :                                             files_struct *fsp,
    1945             :                                             uint32_t share_access,
    1946             :                                             uint32_t access_mask)
    1947             : {
    1948           0 :         errno = ENOSYS;
    1949           0 :         return -1;
    1950             : }
    1951             : 
    1952           0 : static int vfs_gluster_fcntl(vfs_handle_struct *handle,
    1953             :                              files_struct *fsp, int cmd, va_list cmd_arg)
    1954             : {
    1955             :         /*
    1956             :          * SMB_VFS_FCNTL() is currently only called by vfs_set_blocking() to
    1957             :          * clear O_NONBLOCK, etc for LOCK_MAND and FIFOs. Ignore it.
    1958             :          */
    1959           0 :         if (cmd == F_GETFL) {
    1960           0 :                 return 0;
    1961           0 :         } else if (cmd == F_SETFL) {
    1962             :                 va_list dup_cmd_arg;
    1963             :                 int opt;
    1964             : 
    1965           0 :                 va_copy(dup_cmd_arg, cmd_arg);
    1966           0 :                 opt = va_arg(dup_cmd_arg, int);
    1967           0 :                 va_end(dup_cmd_arg);
    1968           0 :                 if (opt == 0) {
    1969           0 :                         return 0;
    1970             :                 }
    1971           0 :                 DBG_ERR("unexpected fcntl SETFL(%d)\n", opt);
    1972           0 :                 goto err_out;
    1973             :         }
    1974           0 :         DBG_ERR("unexpected fcntl: %d\n", cmd);
    1975           0 : err_out:
    1976           0 :         errno = EINVAL;
    1977           0 :         return -1;
    1978             : }
    1979             : 
    1980           0 : static int vfs_gluster_linux_setlease(struct vfs_handle_struct *handle,
    1981             :                                       files_struct *fsp, int leasetype)
    1982             : {
    1983           0 :         errno = ENOSYS;
    1984           0 :         return -1;
    1985             : }
    1986             : 
    1987           0 : static bool vfs_gluster_getlock(struct vfs_handle_struct *handle,
    1988             :                                 files_struct *fsp, off_t *poffset,
    1989             :                                 off_t *pcount, int *ptype, pid_t *ppid)
    1990             : {
    1991           0 :         struct flock flock = { 0, };
    1992             :         int ret;
    1993           0 :         glfs_fd_t *glfd = NULL;
    1994             : 
    1995           0 :         START_PROFILE(syscall_fcntl_getlock);
    1996             : 
    1997           0 :         glfd = vfs_gluster_fetch_glfd(handle, fsp);
    1998           0 :         if (glfd == NULL) {
    1999           0 :                 END_PROFILE(syscall_fcntl_getlock);
    2000           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    2001           0 :                 return false;
    2002             :         }
    2003             : 
    2004           0 :         flock.l_type = *ptype;
    2005           0 :         flock.l_whence = SEEK_SET;
    2006           0 :         flock.l_start = *poffset;
    2007           0 :         flock.l_len = *pcount;
    2008           0 :         flock.l_pid = 0;
    2009             : 
    2010           0 :         ret = glfs_posix_lock(glfd, F_GETLK, &flock);
    2011             : 
    2012           0 :         if (ret == -1) {
    2013           0 :                 END_PROFILE(syscall_fcntl_getlock);
    2014           0 :                 return false;
    2015             :         }
    2016             : 
    2017           0 :         *ptype = flock.l_type;
    2018           0 :         *poffset = flock.l_start;
    2019           0 :         *pcount = flock.l_len;
    2020           0 :         *ppid = flock.l_pid;
    2021           0 :         END_PROFILE(syscall_fcntl_getlock);
    2022             : 
    2023           0 :         return true;
    2024             : }
    2025             : 
    2026           0 : static int vfs_gluster_symlinkat(struct vfs_handle_struct *handle,
    2027             :                                 const struct smb_filename *link_target,
    2028             :                                 struct files_struct *dirfsp,
    2029             :                                 const struct smb_filename *new_smb_fname)
    2030             : {
    2031             :         int ret;
    2032             : 
    2033             : #ifdef HAVE_GFAPI_VER_7_11
    2034             :         glfs_fd_t *pglfd = NULL;
    2035             : 
    2036             :         START_PROFILE(syscall_symlinkat);
    2037             : 
    2038             :         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
    2039             :         if (pglfd == NULL) {
    2040             :                 END_PROFILE(syscall_symlinkat);
    2041             :                 DBG_ERR("Failed to fetch gluster fd\n");
    2042             :                 return -1;
    2043             :         }
    2044             : 
    2045             :         ret = glfs_symlinkat(link_target->base_name,
    2046             :                              pglfd,
    2047             :                              new_smb_fname->base_name);
    2048             : #else
    2049           0 :         struct smb_filename *full_fname = NULL;
    2050             : 
    2051           0 :         START_PROFILE(syscall_symlinkat);
    2052             : 
    2053           0 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
    2054             :                                                   dirfsp,
    2055             :                                                   new_smb_fname);
    2056           0 :         if (full_fname == NULL) {
    2057           0 :                 END_PROFILE(syscall_symlinkat);
    2058           0 :                 return -1;
    2059             :         }
    2060             : 
    2061           0 :         ret = glfs_symlink(handle->data,
    2062           0 :                            link_target->base_name,
    2063           0 :                            full_fname->base_name);
    2064             : 
    2065           0 :         TALLOC_FREE(full_fname);
    2066             : #endif
    2067             : 
    2068           0 :         END_PROFILE(syscall_symlinkat);
    2069             : 
    2070           0 :         return ret;
    2071             : }
    2072             : 
    2073           0 : static int vfs_gluster_readlinkat(struct vfs_handle_struct *handle,
    2074             :                                 const struct files_struct *dirfsp,
    2075             :                                 const struct smb_filename *smb_fname,
    2076             :                                 char *buf,
    2077             :                                 size_t bufsiz)
    2078             : {
    2079             :         int ret;
    2080             : 
    2081             : #ifdef HAVE_GFAPI_VER_7_11
    2082             :         glfs_fd_t *pglfd = NULL;
    2083             : 
    2084             :         START_PROFILE(syscall_readlinkat);
    2085             : 
    2086             :         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
    2087             :         if (pglfd == NULL) {
    2088             :                 END_PROFILE(syscall_readlinkat);
    2089             :                 DBG_ERR("Failed to fetch gluster fd\n");
    2090             :                 return -1;
    2091             :         }
    2092             : 
    2093             :         ret = glfs_readlinkat(pglfd, smb_fname->base_name, buf, bufsiz);
    2094             : #else
    2095           0 :         struct smb_filename *full_fname = NULL;
    2096             : 
    2097           0 :         START_PROFILE(syscall_readlinkat);
    2098             : 
    2099           0 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
    2100             :                                                   dirfsp,
    2101             :                                                   smb_fname);
    2102           0 :         if (full_fname == NULL) {
    2103           0 :                 END_PROFILE(syscall_readlinkat);
    2104           0 :                 return -1;
    2105             :         }
    2106             : 
    2107           0 :         ret = glfs_readlink(handle->data, full_fname->base_name, buf, bufsiz);
    2108             : 
    2109           0 :         TALLOC_FREE(full_fname);
    2110             : #endif
    2111             : 
    2112           0 :         END_PROFILE(syscall_readlinkat);
    2113             : 
    2114           0 :         return ret;
    2115             : }
    2116             : 
    2117           0 : static int vfs_gluster_linkat(struct vfs_handle_struct *handle,
    2118             :                                 files_struct *srcfsp,
    2119             :                                 const struct smb_filename *old_smb_fname,
    2120             :                                 files_struct *dstfsp,
    2121             :                                 const struct smb_filename *new_smb_fname,
    2122             :                                 int flags)
    2123             : {
    2124             :         int ret;
    2125             : 
    2126             : #ifdef HAVE_GFAPI_VER_7_11
    2127             :         glfs_fd_t *src_pglfd = NULL;
    2128             :         glfs_fd_t *dst_pglfd = NULL;
    2129             : 
    2130             :         START_PROFILE(syscall_linkat);
    2131             : 
    2132             :         src_pglfd = vfs_gluster_fetch_glfd(handle, srcfsp);
    2133             :         if (src_pglfd == NULL) {
    2134             :                 END_PROFILE(syscall_linkat);
    2135             :                 DBG_ERR("Failed to fetch gluster fd\n");
    2136             :                 return -1;
    2137             :         }
    2138             : 
    2139             :         dst_pglfd = vfs_gluster_fetch_glfd(handle, dstfsp);
    2140             :         if (dst_pglfd == NULL) {
    2141             :                 END_PROFILE(syscall_linkat);
    2142             :                 DBG_ERR("Failed to fetch gluster fd\n");
    2143             :                 return -1;
    2144             :         }
    2145             : 
    2146             :         ret = glfs_linkat(src_pglfd,
    2147             :                           old_smb_fname->base_name,
    2148             :                           dst_pglfd,
    2149             :                           new_smb_fname->base_name,
    2150             :                           flags);
    2151             : #else
    2152           0 :         struct smb_filename *full_fname_old = NULL;
    2153           0 :         struct smb_filename *full_fname_new = NULL;
    2154             : 
    2155           0 :         START_PROFILE(syscall_linkat);
    2156             : 
    2157           0 :         full_fname_old = full_path_from_dirfsp_atname(talloc_tos(),
    2158             :                                                       srcfsp,
    2159             :                                                       old_smb_fname);
    2160           0 :         if (full_fname_old == NULL) {
    2161           0 :                 END_PROFILE(syscall_linkat);
    2162           0 :                 return -1;
    2163             :         }
    2164             : 
    2165           0 :         full_fname_new = full_path_from_dirfsp_atname(talloc_tos(),
    2166             :                                                       dstfsp,
    2167             :                                                       new_smb_fname);
    2168           0 :         if (full_fname_new == NULL) {
    2169           0 :                 END_PROFILE(syscall_linkat);
    2170           0 :                 TALLOC_FREE(full_fname_old);
    2171           0 :                 return -1;
    2172             :         }
    2173             : 
    2174           0 :         ret = glfs_link(handle->data,
    2175           0 :                         full_fname_old->base_name,
    2176           0 :                         full_fname_new->base_name);
    2177             : 
    2178           0 :         TALLOC_FREE(full_fname_old);
    2179           0 :         TALLOC_FREE(full_fname_new);
    2180             : #endif
    2181             : 
    2182           0 :         END_PROFILE(syscall_linkat);
    2183             : 
    2184           0 :         return ret;
    2185             : }
    2186             : 
    2187           0 : static int vfs_gluster_mknodat(struct vfs_handle_struct *handle,
    2188             :                                 files_struct *dirfsp,
    2189             :                                 const struct smb_filename *smb_fname,
    2190             :                                 mode_t mode,
    2191             :                                 SMB_DEV_T dev)
    2192             : {
    2193             :         int ret;
    2194             : 
    2195             : #ifdef HAVE_GFAPI_VER_7_11
    2196             :         glfs_fd_t *pglfd = NULL;
    2197             : 
    2198             :         START_PROFILE(syscall_mknodat);
    2199             : 
    2200             :         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
    2201             :         if (pglfd == NULL) {
    2202             :                 END_PROFILE(syscall_mknodat);
    2203             :                 DBG_ERR("Failed to fetch gluster fd\n");
    2204             :                 return -1;
    2205             :         }
    2206             : 
    2207             :         ret = glfs_mknodat(pglfd, smb_fname->base_name, mode, dev);
    2208             : #else
    2209           0 :         struct smb_filename *full_fname = NULL;
    2210             : 
    2211           0 :         START_PROFILE(syscall_mknodat);
    2212             : 
    2213           0 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
    2214             :                                                   dirfsp,
    2215             :                                                   smb_fname);
    2216           0 :         if (full_fname == NULL) {
    2217           0 :                 END_PROFILE(syscall_mknodat);
    2218           0 :                 return -1;
    2219             :         }
    2220             : 
    2221           0 :         ret = glfs_mknod(handle->data, full_fname->base_name, mode, dev);
    2222             : 
    2223           0 :         TALLOC_FREE(full_fname);
    2224             : #endif
    2225             : 
    2226           0 :         END_PROFILE(syscall_mknodat);
    2227             : 
    2228           0 :         return ret;
    2229             : }
    2230             : 
    2231           0 : static int vfs_gluster_fchflags(struct vfs_handle_struct *handle,
    2232             :                                 struct files_struct *fsp,
    2233             :                                 unsigned int flags)
    2234             : {
    2235           0 :         errno = ENOSYS;
    2236           0 :         return -1;
    2237             : }
    2238             : 
    2239           0 : static NTSTATUS vfs_gluster_get_real_filename_at(
    2240             :         struct vfs_handle_struct *handle,
    2241             :         struct files_struct *dirfsp,
    2242             :         const char *name,
    2243             :         TALLOC_CTX *mem_ctx,
    2244             :         char **found_name)
    2245             : {
    2246             :         int ret;
    2247             :         char key_buf[GLUSTER_NAME_MAX + 64];
    2248             :         char val_buf[GLUSTER_NAME_MAX + 1];
    2249             : 
    2250           0 :         if (strlen(name) >= GLUSTER_NAME_MAX) {
    2251           0 :                 return NT_STATUS_OBJECT_NAME_INVALID;
    2252             :         }
    2253             : 
    2254           0 :         snprintf(key_buf, GLUSTER_NAME_MAX + 64,
    2255             :                  "glusterfs.get_real_filename:%s", name);
    2256             : 
    2257           0 :         ret = glfs_getxattr(handle->data,
    2258           0 :                             dirfsp->fsp_name->base_name,
    2259             :                             key_buf,
    2260             :                             val_buf,
    2261             :                             GLUSTER_NAME_MAX + 1);
    2262           0 :         if (ret == -1) {
    2263           0 :                 if (errno == ENOATTR) {
    2264           0 :                         errno = ENOENT;
    2265             :                 }
    2266           0 :                 return map_nt_error_from_unix(errno);
    2267             :         }
    2268             : 
    2269           0 :         *found_name = talloc_strdup(mem_ctx, val_buf);
    2270           0 :         if (found_name[0] == NULL) {
    2271           0 :                 return NT_STATUS_NO_MEMORY;
    2272             :         }
    2273             : 
    2274           0 :         return NT_STATUS_OK;
    2275             : }
    2276             : 
    2277           0 : static const char *vfs_gluster_connectpath(struct vfs_handle_struct *handle,
    2278             :                                 const struct smb_filename *smb_fname)
    2279             : {
    2280           0 :         return handle->conn->connectpath;
    2281             : }
    2282             : 
    2283             : /* EA Operations */
    2284             : 
    2285           0 : static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
    2286             :                                      files_struct *fsp, const char *name,
    2287             :                                      void *value, size_t size)
    2288             : {
    2289           0 :         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
    2290           0 :         if (glfd == NULL) {
    2291           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    2292           0 :                 return -1;
    2293             :         }
    2294             : 
    2295           0 :         if (!fsp->fsp_flags.is_pathref) {
    2296             :                 /*
    2297             :                  * We can use an io_fd to retrieve xattr value.
    2298             :                  */
    2299           0 :                 return glfs_fgetxattr(glfd, name, value, size);
    2300             :         }
    2301             : 
    2302             :         /*
    2303             :          * This is no longer a handle based call.
    2304             :          */
    2305           0 :         return glfs_getxattr(handle->data,
    2306           0 :                              fsp->fsp_name->base_name,
    2307             :                              name,
    2308             :                              value,
    2309             :                              size);
    2310             : }
    2311             : 
    2312           0 : static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
    2313             :                                       files_struct *fsp, char *list,
    2314             :                                       size_t size)
    2315             : {
    2316           0 :         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
    2317           0 :         if (glfd == NULL) {
    2318           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    2319           0 :                 return -1;
    2320             :         }
    2321           0 :         if (!fsp->fsp_flags.is_pathref) {
    2322             :                 /*
    2323             :                  * We can use an io_fd to list xattrs.
    2324             :                  */
    2325           0 :                 return glfs_flistxattr(glfd, list, size);
    2326             :         } else {
    2327             :                 /*
    2328             :                  * This is no longer a handle based call.
    2329             :                  */
    2330           0 :                 return glfs_listxattr(handle->data,
    2331           0 :                                 fsp->fsp_name->base_name,
    2332             :                                 list,
    2333             :                                 size);
    2334             :         }
    2335             : }
    2336             : 
    2337           0 : static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
    2338             :                                     files_struct *fsp, const char *name)
    2339             : {
    2340           0 :         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
    2341           0 :         if (glfd == NULL) {
    2342           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    2343           0 :                 return -1;
    2344             :         }
    2345           0 :         if (!fsp->fsp_flags.is_pathref) {
    2346             :                 /*
    2347             :                  * We can use an io_fd to remove xattrs.
    2348             :                  */
    2349           0 :                 return glfs_fremovexattr(glfd, name);
    2350             :         } else {
    2351             :                 /*
    2352             :                  * This is no longer a handle based call.
    2353             :                  */
    2354           0 :                 return glfs_removexattr(handle->data,
    2355           0 :                                 fsp->fsp_name->base_name,
    2356             :                                 name);
    2357             :         }
    2358             : }
    2359             : 
    2360           0 : static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
    2361             :                                  files_struct *fsp, const char *name,
    2362             :                                  const void *value, size_t size, int flags)
    2363             : {
    2364           0 :         glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp);
    2365           0 :         if (glfd == NULL) {
    2366           0 :                 DBG_ERR("Failed to fetch gluster fd\n");
    2367           0 :                 return -1;
    2368             :         }
    2369             : 
    2370           0 :         if (!fsp->fsp_flags.is_pathref) {
    2371             :                 /*
    2372             :                  * We can use an io_fd to set xattrs.
    2373             :                  */
    2374           0 :                 return glfs_fsetxattr(glfd, name, value, size, flags);
    2375             :         } else {
    2376             :                 /*
    2377             :                  * This is no longer a handle based call.
    2378             :                  */
    2379           0 :                 return glfs_setxattr(handle->data,
    2380           0 :                                 fsp->fsp_name->base_name,
    2381             :                                 name,
    2382             :                                 value,
    2383             :                                 size,
    2384             :                                 flags);
    2385             :         }
    2386             : }
    2387             : 
    2388             : /* AIO Operations */
    2389             : 
    2390           0 : static bool vfs_gluster_aio_force(struct vfs_handle_struct *handle,
    2391             :                                   files_struct *fsp)
    2392             : {
    2393           0 :         return false;
    2394             : }
    2395             : 
    2396           0 : static NTSTATUS vfs_gluster_create_dfs_pathat(struct vfs_handle_struct *handle,
    2397             :                                 struct files_struct *dirfsp,
    2398             :                                 const struct smb_filename *smb_fname,
    2399             :                                 const struct referral *reflist,
    2400             :                                 size_t referral_count)
    2401             : {
    2402           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2403           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    2404             :         int ret;
    2405           0 :         char *msdfs_link = NULL;
    2406             : #ifdef HAVE_GFAPI_VER_7_11
    2407             :         glfs_fd_t *pglfd = NULL;
    2408             : #else
    2409           0 :         struct smb_filename *full_fname = NULL;
    2410             : #endif
    2411             : 
    2412             :         /* Form the msdfs_link contents */
    2413           0 :         msdfs_link = msdfs_link_string(frame,
    2414             :                                         reflist,
    2415             :                                         referral_count);
    2416           0 :         if (msdfs_link == NULL) {
    2417           0 :                 goto out;
    2418             :         }
    2419             : 
    2420             : #ifdef HAVE_GFAPI_VER_7_11
    2421             :         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
    2422             :         if (pglfd == NULL) {
    2423             :                 DBG_ERR("Failed to fetch gluster fd\n");
    2424             :                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
    2425             :                 goto out;
    2426             :         }
    2427             : 
    2428             :         ret = glfs_symlinkat(msdfs_link, pglfd, smb_fname->base_name);
    2429             : #else
    2430           0 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
    2431             :                                                   dirfsp,
    2432             :                                                   smb_fname);
    2433           0 :         if (full_fname == NULL) {
    2434           0 :                 goto out;
    2435             :         }
    2436             : 
    2437           0 :         ret = glfs_symlink(handle->data, msdfs_link, full_fname->base_name);
    2438             : 
    2439           0 :         TALLOC_FREE(full_fname);
    2440             : #endif
    2441           0 :         if (ret == 0) {
    2442           0 :                 status = NT_STATUS_OK;
    2443             :         } else {
    2444           0 :                 status = map_nt_error_from_unix(errno);
    2445             :         }
    2446             : 
    2447           0 :   out:
    2448             : 
    2449           0 :         TALLOC_FREE(frame);
    2450           0 :         return status;
    2451             : }
    2452             : 
    2453             : /*
    2454             :  * Read and return the contents of a DFS redirect given a
    2455             :  * pathname. A caller can pass in NULL for ppreflist and
    2456             :  * preferral_count but still determine if this was a
    2457             :  * DFS redirect point by getting NT_STATUS_OK back
    2458             :  * without incurring the overhead of reading and parsing
    2459             :  * the referral contents.
    2460             :  */
    2461             : 
    2462           0 : static NTSTATUS vfs_gluster_read_dfs_pathat(struct vfs_handle_struct *handle,
    2463             :                                 TALLOC_CTX *mem_ctx,
    2464             :                                 struct files_struct *dirfsp,
    2465             :                                 struct smb_filename *smb_fname,
    2466             :                                 struct referral **ppreflist,
    2467             :                                 size_t *preferral_count)
    2468             : {
    2469           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    2470             :         size_t bufsize;
    2471           0 :         char *link_target = NULL;
    2472             :         int referral_len;
    2473             :         bool ok;
    2474             : #if defined(HAVE_BROKEN_READLINK)
    2475             :         char link_target_buf[PATH_MAX];
    2476             : #else
    2477             :         char link_target_buf[7];
    2478             : #endif
    2479             :         struct stat st;
    2480           0 :         struct smb_filename *full_fname = NULL;
    2481             :         int ret;
    2482             : #ifdef HAVE_GFAPI_VER_7_11
    2483             :         glfs_fd_t *pglfd = NULL;
    2484             : #endif
    2485             : 
    2486           0 :         if (is_named_stream(smb_fname)) {
    2487           0 :                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
    2488           0 :                 goto err;
    2489             :         }
    2490             : 
    2491           0 :         if (ppreflist == NULL && preferral_count == NULL) {
    2492             :                 /*
    2493             :                  * We're only checking if this is a DFS
    2494             :                  * redirect. We don't need to return data.
    2495             :                  */
    2496           0 :                 bufsize = sizeof(link_target_buf);
    2497           0 :                 link_target = link_target_buf;
    2498             :         } else {
    2499           0 :                 bufsize = PATH_MAX;
    2500           0 :                 link_target = talloc_array(mem_ctx, char, bufsize);
    2501           0 :                 if (!link_target) {
    2502           0 :                         goto err;
    2503             :                 }
    2504             :         }
    2505             : 
    2506           0 :         full_fname = full_path_from_dirfsp_atname(talloc_tos(),
    2507             :                                                   dirfsp,
    2508             :                                                   smb_fname);
    2509           0 :         if (full_fname == NULL) {
    2510           0 :                 status = NT_STATUS_NO_MEMORY;
    2511           0 :                 goto err;
    2512             :         }
    2513             : 
    2514           0 :         ret = glfs_lstat(handle->data, full_fname->base_name, &st);
    2515           0 :         if (ret < 0) {
    2516           0 :                 status = map_nt_error_from_unix(errno);
    2517           0 :                 goto err;
    2518             :         }
    2519             : 
    2520             : #ifdef HAVE_GFAPI_VER_7_11
    2521             :         pglfd = vfs_gluster_fetch_glfd(handle, dirfsp);
    2522             :         if (pglfd == NULL) {
    2523             :                 DBG_ERR("Failed to fetch gluster fd\n");
    2524             :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    2525             :         }
    2526             : 
    2527             :         referral_len = glfs_readlinkat(pglfd,
    2528             :                                        smb_fname->base_name,
    2529             :                                        link_target,
    2530             :                                        bufsize - 1);
    2531             : #else
    2532           0 :         referral_len = glfs_readlink(handle->data,
    2533           0 :                                 full_fname->base_name,
    2534             :                                 link_target,
    2535             :                                 bufsize - 1);
    2536             : #endif
    2537           0 :         if (referral_len < 0) {
    2538           0 :                 if (errno == EINVAL) {
    2539           0 :                         DBG_INFO("%s is not a link.\n", full_fname->base_name);
    2540           0 :                         status = NT_STATUS_OBJECT_TYPE_MISMATCH;
    2541             :                 } else {
    2542           0 :                         status = map_nt_error_from_unix(errno);
    2543           0 :                         DBG_ERR("Error reading "
    2544             :                                 "msdfs link %s: %s\n",
    2545             :                                 full_fname->base_name,
    2546             :                                 strerror(errno));
    2547             :                 }
    2548           0 :                 goto err;
    2549             :         }
    2550           0 :         link_target[referral_len] = '\0';
    2551             : 
    2552           0 :         DBG_INFO("%s -> %s\n",
    2553             :                         full_fname->base_name,
    2554             :                         link_target);
    2555             : 
    2556           0 :         if (!strnequal(link_target, "msdfs:", 6)) {
    2557           0 :                 status = NT_STATUS_OBJECT_TYPE_MISMATCH;
    2558           0 :                 goto err;
    2559             :         }
    2560             : 
    2561           0 :         if (ppreflist == NULL && preferral_count == NULL) {
    2562             :                 /* Early return for checking if this is a DFS link. */
    2563           0 :                 TALLOC_FREE(full_fname);
    2564           0 :                 smb_stat_ex_from_stat(&smb_fname->st, &st);
    2565           0 :                 return NT_STATUS_OK;
    2566             :         }
    2567             : 
    2568           0 :         ok = parse_msdfs_symlink(mem_ctx,
    2569           0 :                         lp_msdfs_shuffle_referrals(SNUM(handle->conn)),
    2570             :                         link_target,
    2571             :                         ppreflist,
    2572             :                         preferral_count);
    2573             : 
    2574           0 :         if (ok) {
    2575           0 :                 smb_stat_ex_from_stat(&smb_fname->st, &st);
    2576           0 :                 status = NT_STATUS_OK;
    2577             :         } else {
    2578           0 :                 status = NT_STATUS_NO_MEMORY;
    2579             :         }
    2580             : 
    2581           0 :   err:
    2582             : 
    2583           0 :         if (link_target != link_target_buf) {
    2584           0 :                 TALLOC_FREE(link_target);
    2585             :         }
    2586           0 :         TALLOC_FREE(full_fname);
    2587           0 :         return status;
    2588             : }
    2589             : 
    2590             : static struct vfs_fn_pointers glusterfs_fns = {
    2591             : 
    2592             :         /* Disk Operations */
    2593             : 
    2594             :         .connect_fn = vfs_gluster_connect,
    2595             :         .disconnect_fn = vfs_gluster_disconnect,
    2596             :         .disk_free_fn = vfs_gluster_disk_free,
    2597             :         .get_quota_fn = vfs_gluster_get_quota,
    2598             :         .set_quota_fn = vfs_gluster_set_quota,
    2599             :         .statvfs_fn = vfs_gluster_statvfs,
    2600             :         .fs_capabilities_fn = vfs_gluster_fs_capabilities,
    2601             : 
    2602             :         .get_dfs_referrals_fn = NULL,
    2603             : 
    2604             :         /* Directory Operations */
    2605             : 
    2606             :         .fdopendir_fn = vfs_gluster_fdopendir,
    2607             :         .readdir_fn = vfs_gluster_readdir,
    2608             :         .seekdir_fn = vfs_gluster_seekdir,
    2609             :         .telldir_fn = vfs_gluster_telldir,
    2610             :         .rewind_dir_fn = vfs_gluster_rewinddir,
    2611             :         .mkdirat_fn = vfs_gluster_mkdirat,
    2612             :         .closedir_fn = vfs_gluster_closedir,
    2613             : 
    2614             :         /* File Operations */
    2615             : 
    2616             :         .openat_fn = vfs_gluster_openat,
    2617             :         .create_file_fn = NULL,
    2618             :         .close_fn = vfs_gluster_close,
    2619             :         .pread_fn = vfs_gluster_pread,
    2620             :         .pread_send_fn = vfs_gluster_pread_send,
    2621             :         .pread_recv_fn = vfs_gluster_pread_recv,
    2622             :         .pwrite_fn = vfs_gluster_pwrite,
    2623             :         .pwrite_send_fn = vfs_gluster_pwrite_send,
    2624             :         .pwrite_recv_fn = vfs_gluster_pwrite_recv,
    2625             :         .lseek_fn = vfs_gluster_lseek,
    2626             :         .sendfile_fn = vfs_gluster_sendfile,
    2627             :         .recvfile_fn = vfs_gluster_recvfile,
    2628             :         .renameat_fn = vfs_gluster_renameat,
    2629             :         .fsync_send_fn = vfs_gluster_fsync_send,
    2630             :         .fsync_recv_fn = vfs_gluster_fsync_recv,
    2631             : 
    2632             :         .stat_fn = vfs_gluster_stat,
    2633             :         .fstat_fn = vfs_gluster_fstat,
    2634             :         .fstatat_fn = vfs_gluster_fstatat,
    2635             :         .lstat_fn = vfs_gluster_lstat,
    2636             :         .get_alloc_size_fn = vfs_gluster_get_alloc_size,
    2637             :         .unlinkat_fn = vfs_gluster_unlinkat,
    2638             : 
    2639             :         .fchmod_fn = vfs_gluster_fchmod,
    2640             :         .fchown_fn = vfs_gluster_fchown,
    2641             :         .lchown_fn = vfs_gluster_lchown,
    2642             :         .chdir_fn = vfs_gluster_chdir,
    2643             :         .getwd_fn = vfs_gluster_getwd,
    2644             :         .fntimes_fn = vfs_gluster_fntimes,
    2645             :         .ftruncate_fn = vfs_gluster_ftruncate,
    2646             :         .fallocate_fn = vfs_gluster_fallocate,
    2647             :         .lock_fn = vfs_gluster_lock,
    2648             :         .filesystem_sharemode_fn = vfs_gluster_filesystem_sharemode,
    2649             :         .fcntl_fn = vfs_gluster_fcntl,
    2650             :         .linux_setlease_fn = vfs_gluster_linux_setlease,
    2651             :         .getlock_fn = vfs_gluster_getlock,
    2652             :         .symlinkat_fn = vfs_gluster_symlinkat,
    2653             :         .readlinkat_fn = vfs_gluster_readlinkat,
    2654             :         .linkat_fn = vfs_gluster_linkat,
    2655             :         .mknodat_fn = vfs_gluster_mknodat,
    2656             :         .realpath_fn = vfs_gluster_realpath,
    2657             :         .fchflags_fn = vfs_gluster_fchflags,
    2658             :         .file_id_create_fn = NULL,
    2659             :         .fstreaminfo_fn = NULL,
    2660             :         .get_real_filename_at_fn = vfs_gluster_get_real_filename_at,
    2661             :         .connectpath_fn = vfs_gluster_connectpath,
    2662             :         .create_dfs_pathat_fn = vfs_gluster_create_dfs_pathat,
    2663             :         .read_dfs_pathat_fn = vfs_gluster_read_dfs_pathat,
    2664             : 
    2665             :         .brl_lock_windows_fn = NULL,
    2666             :         .brl_unlock_windows_fn = NULL,
    2667             :         .strict_lock_check_fn = NULL,
    2668             :         .translate_name_fn = NULL,
    2669             :         .fsctl_fn = NULL,
    2670             : 
    2671             :         /* NT ACL Operations */
    2672             :         .fget_nt_acl_fn = NULL,
    2673             :         .fset_nt_acl_fn = NULL,
    2674             :         .audit_file_fn = NULL,
    2675             : 
    2676             :         /* Posix ACL Operations */
    2677             :         .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
    2678             :         .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
    2679             :         .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
    2680             :         .sys_acl_delete_def_fd_fn = posixacl_xattr_acl_delete_def_fd,
    2681             : 
    2682             :         /* EA Operations */
    2683             :         .getxattrat_send_fn = vfs_not_implemented_getxattrat_send,
    2684             :         .getxattrat_recv_fn = vfs_not_implemented_getxattrat_recv,
    2685             :         .fgetxattr_fn = vfs_gluster_fgetxattr,
    2686             :         .flistxattr_fn = vfs_gluster_flistxattr,
    2687             :         .fremovexattr_fn = vfs_gluster_fremovexattr,
    2688             :         .fsetxattr_fn = vfs_gluster_fsetxattr,
    2689             : 
    2690             :         /* AIO Operations */
    2691             :         .aio_force_fn = vfs_gluster_aio_force,
    2692             : 
    2693             :         /* Durable handle Operations */
    2694             :         .durable_cookie_fn = NULL,
    2695             :         .durable_disconnect_fn = NULL,
    2696             :         .durable_reconnect_fn = NULL,
    2697             : };
    2698             : 
    2699             : static_decl_vfs;
    2700          26 : NTSTATUS vfs_glusterfs_init(TALLOC_CTX *ctx)
    2701             : {
    2702          26 :         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
    2703             :                                 "glusterfs", &glusterfs_fns);
    2704             : }

Generated by: LCOV version 1.13