1    	/*
2    	 * vim:noexpandtab:shiftwidth=8:tabstop=8:
3    	 *
4    	 * Copyright (C) Red Hat  Inc., 2011
5    	 * Author: Anand Subramanian anands@redhat.com
6    	 *
7    	 * This program is free software; you can redistribute it and/or
8    	 * modify it under the terms of the GNU Lesser General Public
9    	 * License as published by the Free Software Foundation; either
10   	 * version 3 of the License, or (at your option) any later version.
11   	 *
12   	 * This program is distributed in the hope that it will be useful,
13   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   	 * Lesser General Public License for more details.
16   	 *
17   	 * You should have received a copy of the GNU Lesser General Public
18   	 * License along with this library; if not, write to the Free Software
19   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
20   	 *
21   	 * -------------
22   	 */
23   	
24   	/* main.c
25   	 * Module core functions
26   	 */
27   	
28   	#include <sys/types.h>
29   	#include "os/xattr.h"
30   	#include "gluster_internal.h"
31   	#include "fsal_api.h"
32   	#include "fsal_convert.h"
33   	#include "nfs4_acls.h"
34   	#include "FSAL/fsal_commonlib.h"
35   	#include "posix_acls.h"
36   	#include "nfs_exports.h"
37   	
38   	/**
39   	 * @brief FSAL status mapping from GlusterFS errors
40   	 *
41   	 * This function returns a fsal_status_t with the FSAL error as the
42   	 * major, and the posix error as minor. Please note that this routine
43   	 * needs to be used only in case of failures.
44   	 *
45   	 * @param[in] gluster_errorcode Gluster error
46   	 *
47   	 * @return FSAL status.
48   	 */
49   	
50   	fsal_status_t gluster2fsal_error(const int err)
51   	{
52   		fsal_status_t status;
53   		int g_err = err;
54   	
55   		if (!g_err) {
56   			LogWarn(COMPONENT_FSAL, "appropriate errno not set");
57   			g_err = EINVAL;
58   		}
59   		status.minor = g_err;
60   		status.major = posix2fsal_error(g_err);
61   	
62   		return status;
63   	}
64   	
65   	/**
66   	 * @brief Convert a struct stat from Gluster to a struct attrlist
67   	 *
68   	 * This function writes the content of the supplied struct stat to the
69   	 * struct fsalsattr.
70   	 *
71   	 * @param[in]  buffstat Stat structure
72   	 * @param[out] fsalattr FSAL attributes
73   	 */
74   	
75   	void stat2fsal_attributes(const struct stat *buffstat,
76   				  struct attrlist *fsalattr)
77   	{
78   		/* Indicate which atrributes we have set without affecting the
79   		 * other bits in the mask.
80   		 */
81   		fsalattr->valid_mask |= ATTRS_POSIX;
82   		fsalattr->supported = op_ctx->fsal_export->exp_ops.fs_supported_attrs(
83   								op_ctx->fsal_export);
84   	
85   		/* Fills the output struct */
86   		fsalattr->type = posix2fsal_type(buffstat->st_mode);
87   	
88   		fsalattr->filesize = buffstat->st_size;
89   	
90   		fsalattr->fsid = posix2fsal_fsid(buffstat->st_dev);
91   	
92   		fsalattr->fileid = buffstat->st_ino;
93   	
94   		fsalattr->mode = unix2fsal_mode(buffstat->st_mode);
95   	
96   		fsalattr->numlinks = buffstat->st_nlink;
97   	
98   		fsalattr->owner = buffstat->st_uid;
99   	
100  		fsalattr->group = buffstat->st_gid;
101  	
102  		/** @todo: gfapi currently only fills in the legacy time_t fields
103  		 *         when it supports the timespec fields calls to this
104  		 *         function should be replaced with calls to
105  		 *         posix2fsal_attributes rather than changing this code.
106  		 */
107  		fsalattr->atime = posix2fsal_time(buffstat->st_atime, 0);
108  		fsalattr->ctime = posix2fsal_time(buffstat->st_ctime, 0);
109  		fsalattr->mtime = posix2fsal_time(buffstat->st_mtime, 0);
110  	
111  		fsalattr->change = MAX(buffstat->st_mtime, buffstat->st_ctime);
112  	
113  		fsalattr->spaceused = buffstat->st_blocks * S_BLKSIZE;
114  	
115  		fsalattr->rawdev = posix2fsal_devt(buffstat->st_rdev);
116  	
117  		/* Disable seclabels if not enabled in config */
118  		if (!op_ctx_export_has_option(EXPORT_OPTION_SECLABEL_SET))
119  			fsalattr->supported &= ~ATTR4_SEC_LABEL;
120  	}
121  	
122  	/**
123  	 * @brief Construct a new filehandle
124  	 *
125  	 * This function constructs a new Gluster FSAL object handle and attaches
126  	 * it to the export.  After this call the attributes have been filled
127  	 * in and the handdle is up-to-date and usable.
128  	 *
129  	 * @param[in]  st     Stat data for the file
130  	 * @param[in]  export Export on which the object lives
131  	 * @param[out] obj    Object created
132  	 *
133  	 * @return 0 on success, negative error codes on failure.
134  	 */
135  	
136  	void construct_handle(struct glusterfs_export *glexport, const struct stat *st,
137  			      struct glfs_object *glhandle, unsigned char *globjhdl,
138  			      struct glusterfs_handle **obj, const char *vol_uuid)
139  	{
140  		struct glusterfs_handle *constructing = NULL;
141  	
(6) Event example_assign: Example 3: Assigning: "p_" = return value from "calloc(1UL, 360UL)".
(7) Event example_checked: Example 3 (cont.): "p_" has its value checked in "p_ == NULL".
Also see events: [returned_null][example_assign][example_checked][example_assign][example_checked][example_assign][example_checked][example_assign][example_checked][var_assigned][dereference]
142  		constructing = gsh_calloc(1, sizeof(struct glusterfs_handle));
143  	
144  		constructing->glhandle = glhandle;
145  		memcpy(constructing->globjhdl, vol_uuid, GLAPI_UUID_LENGTH);
146  		memcpy(constructing->globjhdl+GLAPI_UUID_LENGTH, globjhdl,
147  		       GFAPI_HANDLE_LENGTH);
148  		constructing->globalfd.glfd = NULL;
149  	
150  		fsal_obj_handle_init(&constructing->handle, &glexport->export,
151  				     posix2fsal_type(st->st_mode));
152  		constructing->handle.fsid = posix2fsal_fsid(st->st_dev);
153  		constructing->handle.fileid = st->st_ino;
154  		constructing->handle.obj_ops = &GlusterFS.handle_ops;
155  	
156  		*obj = constructing;
157  	}
158  	
159  	void gluster_cleanup_vars(struct glfs_object *glhandle)
160  	{
161  		if (glhandle) {
162  			/* Error ignored, this is a cleanup operation, can't do much. */
163  			/** @todo: Useful point for logging? */
164  			glfs_h_close(glhandle);
165  		}
166  	}
167  	
168  	/* fs_specific_has() parses the fs_specific string for a particular key,
169  	 * returns true if found, and optionally returns a val if the string is
170  	 * of the form key=val.
171  	 *
172  	 * The fs_specific string is a comma (,) separated options where each option
173  	 * can be of the form key=value or just key. Example:
174  	 *	FS_specific = "foo=baz,enable_A";
175  	 */
176  	bool fs_specific_has(const char *fs_specific, const char *key, char *val,
177  			     int *max_val_bytes)
178  	{
179  		char *next_comma, *option;
180  		bool ret;
181  		char *fso_dup = NULL;
182  	
183  		if (!fs_specific || !fs_specific[0])
184  			return false;
185  	
186  		fso_dup = gsh_strdup(fs_specific);
187  	
188  		for (option = strtok_r(fso_dup, ",", &next_comma); option;
189  		     option = strtok_r(NULL, ",", &next_comma)) {
190  			char *k = option;
191  			char *v = k;
192  	
193  			strsep(&v, "=");
194  			if (strcmp(k, key) == 0) {
195  				if (val)
196  					strncpy(val, v, *max_val_bytes);
197  				if (max_val_bytes)
198  					*max_val_bytes = strlen(v) + 1;
199  				ret = true;
200  				goto cleanup;
201  			}
202  		}
203  	
204  		ret = false;
205  	 cleanup:
206  		gsh_free(fso_dup);
207  		return ret;
208  	}
209  	
210  	void setglustercreds(struct glusterfs_export *glfs_export, uid_t *uid,
211  			     gid_t *gid, unsigned int ngrps, gid_t *groups,
212  			     char *client_addr, unsigned int client_addr_len,
213  			     char *file, int line, char *function)
214  	{
215  		int rc = 0;
216  	#ifdef USE_GLUSTER_DELEGATION
217  		char lease_id[GLAPI_LEASE_ID_SIZE];
218  	#endif
219  	
220  		if (uid) {
221  			if (*uid != glfs_export->saveduid)
222  				rc = glfs_setfsuid(*uid);
223  		} else {
224  			rc = glfs_setfsuid(glfs_export->saveduid);
225  		}
226  		if (rc)
227  			goto out;
228  	
229  		if (gid) {
230  			if (*gid != glfs_export->savedgid)
231  				rc = glfs_setfsgid(*gid);
232  		} else {
233  			rc = glfs_setfsgid(glfs_export->savedgid);
234  		}
235  		if (rc)
236  			goto out;
237  	
238  		if (ngrps != 0 && groups)
239  			rc = glfs_setfsgroups(ngrps, groups);
240  		else
241  			rc = glfs_setfsgroups(0, NULL);
242  	
243  	#ifdef USE_GLUSTER_DELEGATION
244  		if ((client_addr_len <= GLAPI_LEASE_ID_SIZE) && client_addr) {
245  			memset(lease_id, 0, GLFS_LEASE_ID_SIZE);
246  			memcpy(lease_id, client_addr, client_addr_len);
247  			rc = glfs_setfsleaseid(lease_id);
248  		} else
249  			rc = glfs_setfsleaseid(NULL);
250  	#endif
251  	 out:
252  		if (rc != 0) {
253  			DisplayLogComponentLevel(COMPONENT_FSAL, file, line, function,
254  				 NIV_FATAL,
255  				"Could not set Gluster credentials - uid(%d), gid(%d)",
256  				uid ? *uid : glfs_export->saveduid,
257  				gid ? *gid : glfs_export->savedgid);
258  		}
259  	}
260  	
261  	/*
262  	 * Read the ACL in GlusterFS format and convert it into fsal ACL before
263  	 * storing it in fsalattr
264  	 */
265  	fsal_status_t glusterfs_get_acl(struct glusterfs_export *glfs_export,
266  					struct glfs_object *glhandle,
267  					glusterfs_fsal_xstat_t *buffxstat,
268  					struct attrlist *fsalattr)
269  	{
270  		fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
271  		fsal_acl_data_t acldata;
272  		fsal_acl_status_t aclstatus;
273  		fsal_ace_t *pace = NULL;
274  		int e_count = 0, i_count = 0, new_count = 0, new_i_count = 0;
275  	
276  		if (fsalattr->acl != NULL) {
277  			/* We should never be passed attributes that have an
278  			 * ACL attached, but just in case some future code
279  			 * path changes that assumption, let's release the
280  			 * old ACL properly.
281  			 */
282  			int acl_status;
283  	
284  			acl_status = nfs4_acl_release_entry(fsalattr->acl);
285  	
286  			if (acl_status != NFS_V4_ACL_SUCCESS)
287  				LogCrit(COMPONENT_FSAL,
288  					"Failed to release old acl, status=%d",
289  					acl_status);
290  	
291  			fsalattr->acl = NULL;
292  		}
293  	
294  		if (NFSv4_ACL_SUPPORT) {
295  	
296  			buffxstat->e_acl = glfs_h_acl_get(glfs_export->gl_fs->fs,
297  							glhandle, ACL_TYPE_ACCESS);
298  	
299  			if (!buffxstat->e_acl) {
300  				status = gluster2fsal_error(errno);
301  				return status;
302  			}
303  	
304  			e_count = ace_count(buffxstat->e_acl);
305  	
306  			if (buffxstat->is_dir) {
307  				buffxstat->i_acl =
308  						 glfs_h_acl_get(glfs_export->gl_fs->fs,
309  							glhandle, ACL_TYPE_DEFAULT);
310  				i_count = ace_count(buffxstat->i_acl);
311  			}
312  	
313  			/* Allocating memory for both ALLOW and DENY entries */
314  			acldata.naces = 2 * (e_count  + i_count);
315  	
316  			LogDebug(COMPONENT_FSAL, "No of aces present in fsal_acl_t = %d"
317  						, acldata.naces);
318  			if (!acldata.naces)
319  				return status;
320  	
321  			FSAL_SET_MASK(buffxstat->attr_valid, XATTR_ACL);
322  	
323  			acldata.aces = (fsal_ace_t *) nfs4_ace_alloc(acldata.naces);
324  			pace = acldata.aces;
325  	
326  			new_count = posix_acl_2_fsal_acl(buffxstat->e_acl,
327  						buffxstat->is_dir, false, &pace);
328  			if (new_count < 0)
329  				return fsalstat(ERR_FSAL_NO_ACE, -1);
330  	
331  			if (i_count > 0) {
332  				new_i_count = posix_acl_2_fsal_acl(buffxstat->i_acl,
333  								true, true, &pace);
334  				if (new_i_count > 0)
335  					new_count += new_i_count;
336  				else
337  					LogDebug(COMPONENT_FSAL,
338  					"Inherit acl is not set for this directory");
339  			}
340  	
341  			/* Reallocating acldata into the required size */
342  			acldata.aces = (fsal_ace_t *) gsh_realloc(acldata.aces,
343  					new_count*sizeof(fsal_ace_t));
344  			acldata.naces = new_count;
345  	
346  			fsalattr->acl = nfs4_acl_new_entry(&acldata, &aclstatus);
347  			LogDebug(COMPONENT_FSAL, "fsal acl = %p, fsal_acl_status = %u",
348  					fsalattr->acl, aclstatus);
349  			if (fsalattr->acl == NULL) {
350  				LogCrit(COMPONENT_FSAL,
351  				"failed to create a new acl entry");
352  				return fsalstat(ERR_FSAL_NOMEM, -1);
353  			}
354  	
355  			fsalattr->valid_mask |= ATTR_ACL;
356  		} else {
357  			/* We were asked for ACL but do not support. */
358  			status = fsalstat(ERR_FSAL_NOTSUPP, 0);
359  		}
360  	
361  		return status;
362  	
363  	}
364  	
365  	/*
366  	 * Store the Glusterfs ACL using setxattr call.
367  	 */
368  	fsal_status_t glusterfs_set_acl(struct glusterfs_export *glfs_export,
369  					struct glusterfs_handle *objhandle,
370  					glusterfs_fsal_xstat_t *buffxstat)
371  	{
372  		int rc = 0;
373  	
374  		rc = glfs_h_acl_set(glfs_export->gl_fs->fs, objhandle->glhandle,
375  					ACL_TYPE_ACCESS, buffxstat->e_acl);
376  		if (rc < 0) {
377  			/** @todo: check if error is appropriate.*/
378  			LogMajor(COMPONENT_FSAL, "failed to set access type posix acl");
379  			return fsalstat(ERR_FSAL_INVAL, 0);
380  		}
381  		/* For directories consider inherited acl too */
382  		if (buffxstat->is_dir && buffxstat->i_acl) {
383  			rc = glfs_h_acl_set(glfs_export->gl_fs->fs, objhandle->glhandle,
384  					ACL_TYPE_DEFAULT, buffxstat->i_acl);
385  			if (rc < 0) {
386  				LogMajor(COMPONENT_FSAL,
387  					 "failed to set default type posix acl");
388  				return fsalstat(ERR_FSAL_INVAL, 0);
389  			}
390  		}
391  		return fsalstat(ERR_FSAL_NO_ERROR, 0);
392  	}
393  	
394  	/*
395  	 *  Process NFSv4 ACLs passed in setattr call
396  	 */
397  	fsal_status_t glusterfs_process_acl(struct glfs *fs,
398  					    struct glfs_object *object,
399  					    struct attrlist *attrs,
400  					    glusterfs_fsal_xstat_t *buffxstat)
401  	{
402  		LogDebug(COMPONENT_FSAL, "setattr acl = %p", attrs->acl);
403  	
404  		/* Convert FSAL ACL to POSIX ACL */
405  		buffxstat->e_acl = fsal_acl_2_posix_acl(attrs->acl, ACL_TYPE_ACCESS);
406  		if (!buffxstat->e_acl) {
407  			LogMajor(COMPONENT_FSAL,
408  				 "failed to set access type posix acl");
409  			return fsalstat(ERR_FSAL_FAULT, 0);
410  		}
411  		/* For directories consider inherited acl too */
412  		if (buffxstat->is_dir) {
413  			buffxstat->i_acl = fsal_acl_2_posix_acl(attrs->acl,
414  								ACL_TYPE_DEFAULT);
415  			if (!buffxstat->i_acl)
416  				LogDebug(COMPONENT_FSAL,
417  					 "inherited acl is not defined for directory");
418  		}
419  	
420  		return fsalstat(ERR_FSAL_NO_ERROR, 0);
421  	}
422  	
423  	int initiate_up_thread(struct glusterfs_fs *gl_fs)
424  	{
425  	
426  		pthread_attr_t up_thr_attr;
427  		int retval  = -1;
428  		int err   = 0;
429  		int retries = 10;
430  	
431  		memset(&up_thr_attr, 0, sizeof(up_thr_attr));
432  	
433  		/* Initialization of thread attributes from nfs_init.c */
434  		err = pthread_attr_init(&up_thr_attr);
435  		if (err) {
436  			LogCrit(COMPONENT_THREAD,
437  				"can't init pthread's attributes (%s)",
438  				strerror(err));
439  			goto out;
440  		}
441  	
442  		err = pthread_attr_setscope(&up_thr_attr,
443  					      PTHREAD_SCOPE_SYSTEM);
444  		if (err) {
445  			LogCrit(COMPONENT_THREAD,
446  				"can't set pthread's scope (%s)",
447  				strerror(err));
448  			goto out;
449  		}
450  	
451  		err = pthread_attr_setdetachstate(&up_thr_attr,
452  						  PTHREAD_CREATE_JOINABLE);
453  		if (err) {
454  			LogCrit(COMPONENT_THREAD,
455  				"can't set pthread's join state (%s)",
456  				strerror(err));
457  			goto out;
458  		}
459  	
460  		err = pthread_attr_setstacksize(&up_thr_attr, 2116488);
461  		if (err) {
462  			LogCrit(COMPONENT_THREAD,
463  				"can't set pthread's stack size (%s)",
464  				strerror(err));
465  			goto out;
466  		}
467  	
468  		do {
469  			err = pthread_create(&gl_fs->up_thread,
470  					     &up_thr_attr,
471  					     GLUSTERFSAL_UP_Thread,
472  					     gl_fs);
473  			sleep(1);
474  		} while (err && (err == EAGAIN) && (retries-- > 0));
475  	
476  		if (err) {
477  			LogCrit(COMPONENT_THREAD,
478  				"can't create upcall pthread (%s)",
479  				strerror(err));
480  			goto out;
481  		}
482  	
483  		retval = 0;
484  	
485  	out:
486  		err = pthread_attr_destroy(&up_thr_attr);
487  		if (err) {
488  			LogCrit(COMPONENT_THREAD,
489  				"can't destroy pthread's attributes (%s)",
490  				strerror(err));
491  		}
492  	
493  		return retval;
494  	}
495  	
496  	#ifdef GLTIMING
497  	void latency_update(struct timespec *s_time, struct timespec *e_time, int opnum)
498  	{
499  		atomic_add_uint64_t(&glfsal_latencies[opnum].overall_time,
500  				    timespec_diff(s_time, e_time));
501  		atomic_add_uint64_t(&glfsal_latencies[opnum].count, 1);
502  	}
503  	
504  	void latency_dump(void)
505  	{
506  		int i = 0;
507  	
508  		for (; i < LATENCY_SLOTS; i++) {
509  			LogCrit(COMPONENT_FSAL, "Op:%d:Count:%"PRIu64":nsecs:%"PRIu64,
510  				i, glfsal_latencies[i].count,
511  				glfsal_latencies[i].overall_time);
512  		}
513  	}
514  	#endif
515