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