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(&times[0],
1553 			      &smb_fname->st.st_ex_atime) == 0) &&
1554 	    (timespec_compare(&times[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