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

Generated by: LCOV version 1.13