1    	/*
2    	 * vim:noexpandtab:shiftwidth=8:tabstop=8:
3    	 *
4    	 * Copyright 2017-2019 Red Hat, Inc.
5    	 * Author: Daniel Gryniewicz  dang@redhat.com
6    	 *
7    	 *
8    	 * This program is free software; you can redistribute it and/or
9    	 * modify it under the terms of the GNU Lesser General Public
10   	 * License as published by the Free Software Foundation; either
11   	 * version 3 of the License, or (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 GNU
16   	 * Lesser General Public License for more details.
17   	 *
18   	 * You should have received a copy of the GNU Lesser General Public
19   	 * License along with this library; if not, write to the Free Software
20   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21   	 * 02110-1301 USA
22   	 *
23   	 * -------------
24   	 */
25   	
26   	/* export.c
27   	 * MEM FSAL export object
28   	 */
29   	
30   	#include "config.h"
31   	
32   	#include "fsal.h"
33   	#include <libgen.h>		/* used for 'dirname' */
34   	#include <pthread.h>
35   	#include <string.h>
36   	#include <sys/types.h>
37   	#include <os/mntent.h>
38   	#include <os/quota.h>
39   	#include <dlfcn.h>
40   	#include "fsal_convert.h"
41   	#include "FSAL/fsal_commonlib.h"
42   	#include "FSAL/fsal_config.h"
43   	#include "mem_int.h"
44   	#include "nfs_exports.h"
45   	#include "nfs_core.h"
46   	#include "export_mgr.h"
47   	
48   	#ifdef __FreeBSD__
49   	#include <sys/endian.h>
50   	
51   	#define bswap_16(x)     bswap16((x))
52   	#define bswap_64(x)     bswap64((x))
53   	#endif
54   	
55   	#ifdef USE_LTTNG
56   	#include "gsh_lttng/fsal_mem.h"
57   	#endif
58   	/* helpers to/from other MEM objects
59   	 */
60   	
61   	/* export object methods
62   	 */
63   	
64   	static void mem_release_export(struct fsal_export *exp_hdl)
65   	{
66   		struct mem_fsal_export *myself;
67   	
68   		myself = container_of(exp_hdl, struct mem_fsal_export, export);
69   	
70   		if (myself->root_handle != NULL) {
71   			mem_clean_export(myself->root_handle);
72   	
73   			fsal_obj_handle_fini(&myself->root_handle->obj_handle);
74   	
75   			LogDebug(COMPONENT_FSAL,
76   				 "Releasing hdl=%p, name=%s",
77   				 myself->root_handle, myself->root_handle->m_name);
78   	
79   			PTHREAD_RWLOCK_wrlock(&myself->mfe_exp_lock);
80   			mem_free_handle(myself->root_handle);
81   			PTHREAD_RWLOCK_unlock(&myself->mfe_exp_lock);
82   	
83   			myself->root_handle = NULL;
84   		}
85   	
86   		fsal_detach_export(exp_hdl->fsal, &exp_hdl->exports);
87   		free_export_ops(exp_hdl);
88   	
89   		glist_del(&myself->export_entry);
90   	
91   		gsh_free(myself->export_path);
92   		gsh_free(myself);
93   	}
94   	
95   	static fsal_status_t mem_get_dynamic_info(struct fsal_export *exp_hdl,
96   						  struct fsal_obj_handle *obj_hdl,
97   						  fsal_dynamicfsinfo_t *infop)
98   	{
99   		infop->total_bytes = 0;
100  		infop->free_bytes = 0;
101  		infop->avail_bytes = 0;
102  		infop->total_files = 0;
103  		infop->free_files = 0;
104  		infop->avail_files = 0;
105  		infop->time_delta.tv_sec = 1;
106  		infop->time_delta.tv_nsec = 0;
107  	
108  		return fsalstat(ERR_FSAL_NO_ERROR, 0);
109  	}
110  	
111  	/* extract a file handle from a buffer.
112  	 * do verification checks and flag any and all suspicious bits.
113  	 * Return an updated fh_desc into whatever was passed.  The most
114  	 * common behavior, done here is to just reset the length.  There
115  	 * is the option to also adjust the start pointer.
116  	 */
117  	
118  	static fsal_status_t mem_wire_to_host(struct fsal_export *exp_hdl,
119  					      fsal_digesttype_t in_type,
120  					      struct gsh_buffdesc *fh_desc,
121  					      int flags)
122  	{
123  		size_t fh_min;
124  		uint64_t *hashkey;
125  		ushort *len;
126  	
127  		fh_min = 1;
128  	
129  		if (fh_desc->len < fh_min) {
130  			LogMajor(COMPONENT_FSAL,
131  				 "Size mismatch for handle.  should be >= %zu, got %zu",
132  				 fh_min, fh_desc->len);
133  			return fsalstat(ERR_FSAL_SERVERFAULT, 0);
134  		}
135  		hashkey = (uint64_t *)fh_desc->addr;
136  		len = (ushort *)((char *)hashkey + sizeof(uint64_t));
137  		if (flags & FH_FSAL_BIG_ENDIAN) {
138  	#if (BYTE_ORDER != BIG_ENDIAN)
139  			*len = bswap_16(*len);
140  			*hashkey = bswap_64(*hashkey);
141  	#endif
142  		} else {
143  	#if (BYTE_ORDER == BIG_ENDIAN)
144  			*len = bswap_16(*len);
145  			*hashkey = bswap_64(*hashkey);
146  	#endif
147  		}
148  		return fsalstat(ERR_FSAL_NO_ERROR, 0);
149  	}
150  	
151  	/**
152  	 * @brief Allocate a state_t structure
153  	 *
154  	 * Note that this is not expected to fail since memory allocation is
155  	 * expected to abort on failure.
156  	 *
157  	 * @param[in] exp_hdl               Export state_t will be associated with
158  	 * @param[in] state_type            Type of state to allocate
159  	 * @param[in] related_state         Related state if appropriate
160  	 *
161  	 * @returns a state structure.
162  	 */
163  	
164  	static struct state_t *mem_alloc_state(struct fsal_export *exp_hdl,
165  					       enum state_type state_type,
166  					       struct state_t *related_state)
167  	{
168  		struct state_t *state;
169  	
(8) Event example_assign: Example 4: Assigning: "p_" = return value from "calloc(1UL, 226UL)".
(9) Event example_checked: Example 4 (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]
170  		state = init_state(gsh_calloc(1, sizeof(struct state_t)
171  					      + sizeof(struct fsal_fd)),
172  				   exp_hdl, state_type, related_state);
173  	#ifdef USE_LTTNG
174  		tracepoint(fsalmem, mem_alloc_state, __func__, __LINE__, state);
175  	#endif
176  		return state;
177  	}
178  	
179  	/* mem_export_ops_init
180  	 * overwrite vector entries with the methods that we support
181  	 */
182  	
183  	void mem_export_ops_init(struct export_ops *ops)
184  	{
185  		ops->release = mem_release_export;
186  		ops->lookup_path = mem_lookup_path;
187  		ops->wire_to_host = mem_wire_to_host;
188  		ops->create_handle = mem_create_handle;
189  		ops->get_fs_dynamic_info = mem_get_dynamic_info;
190  		ops->alloc_state = mem_alloc_state;
191  	}
192  	
193  	const char *str_async_type(uint32_t async_type)
194  	{
195  		switch (async_type) {
196  		case MEM_INLINE:
197  			return "INLINE";
198  		case MEM_RANDOM_OR_INLINE:
199  			return "RANDOM_OR_INLINE";
200  		case MEM_RANDOM:
201  			return "RANDOM";
202  		case MEM_FIXED:
203  			return "FIXED";
204  		}
205  	
206  		return "UNKNOWN";
207  	}
208  	
209  	static struct config_item_list async_types_conf[] = {
210  		CONFIG_LIST_TOK("inline",		MEM_INLINE),
211  		CONFIG_LIST_TOK("fixed",		MEM_FIXED),
212  		CONFIG_LIST_TOK("random",		MEM_RANDOM),
213  		CONFIG_LIST_TOK("random_or_inline",	MEM_RANDOM_OR_INLINE),
214  		CONFIG_LIST_EOL
215  	};
216  	
217  	static struct config_item mem_export_params[] = {
218  		CONF_ITEM_NOOP("name"),
219  		CONF_ITEM_UI32("Async_Delay", 0, 1000, 0,
220  			       mem_fsal_export, async_delay),
221  		CONF_ITEM_TOKEN("Async_Type", MEM_INLINE, async_types_conf,
222  				mem_fsal_export, async_type),
223  		CONF_ITEM_UI32("Async_Stall_Delay", 0, 1000, 0,
224  			       mem_fsal_export, async_stall_delay),
225  		CONFIG_EOL
226  	};
227  	
228  	static struct config_block mem_export_param_block = {
229  		.dbus_interface_name = "org.ganesha.nfsd.config.fsal.mem-export%d",
230  		.blk_desc.name = "FSAL",
231  		.blk_desc.type = CONFIG_BLOCK,
232  		.blk_desc.u.blk.init = noop_conf_init,
233  		.blk_desc.u.blk.params = mem_export_params,
234  		.blk_desc.u.blk.commit = noop_conf_commit
235  	};
236  	
237  	/* create_export
238  	 * Create an export point and return a handle to it to be kept
239  	 * in the export list.
240  	 * First lookup the fsal, then create the export and then put the fsal back.
241  	 * returns the export with one reference taken.
242  	 */
243  	
244  	fsal_status_t mem_create_export(struct fsal_module *fsal_hdl,
245  					void *parse_node,
246  					struct config_error_type *err_type,
247  					const struct fsal_up_vector *up_ops)
248  	{
249  		struct mem_fsal_export *myself;
250  		int retval = 0;
251  		pthread_rwlockattr_t attrs;
252  		fsal_status_t fsal_status = {0, 0};
253  	
254  		myself = gsh_calloc(1, sizeof(struct mem_fsal_export));
255  	
256  		glist_init(&myself->mfe_objs);
257  		pthread_rwlockattr_init(&attrs);
258  	#ifdef GLIBC
259  		pthread_rwlockattr_setkind_np(&attrs,
260  			PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
261  	#endif
262  		PTHREAD_RWLOCK_init(&myself->mfe_exp_lock, &attrs);
263  		pthread_rwlockattr_destroy(&attrs);
264  		fsal_export_init(&myself->export);
265  		mem_export_ops_init(&myself->export.exp_ops);
266  	
267  		retval = load_config_from_node(parse_node,
268  					       &mem_export_param_block,
269  					       myself,
270  					       true,
271  					       err_type);
272  	
273  		if (retval != 0) {
274  			fsal_status = posix2fsal_status(EINVAL);
275  			goto err_free;	/* seriously bad */
276  		}
277  	
278  		retval = fsal_attach_export(fsal_hdl, &myself->export.exports);
279  	
280  		if (retval != 0) {
281  			/* seriously bad */
282  			LogMajor(COMPONENT_FSAL,
283  				 "Could not attach export");
284  			fsal_status = posix2fsal_status(retval);
285  			goto err_free;	/* seriously bad */
286  		}
287  	
288  		myself->export.fsal = fsal_hdl;
289  		myself->export.up_ops = up_ops;
290  	
291  		/* Save the export path. */
292  		myself->export_path = gsh_strdup(op_ctx->ctx_export->fullpath);
293  		op_ctx->fsal_export = &myself->export;
294  	
295  		/* Insert into exports list */
296  		glist_add_tail(&MEM.mem_exports, &myself->export_entry);
297  	
298  		LogDebug(COMPONENT_FSAL,
299  			 "Created exp %p - %s",
300  			 myself, myself->export_path);
301  	
302  		return fsalstat(ERR_FSAL_NO_ERROR, 0);
303  	
304  	err_free:
305  		free_export_ops(&myself->export);
306  		gsh_free(myself);	/* elvis has left the building */
307  		return fsal_status;
308  	}
309  	
310  	/**
311  	 * @brief Update an existing export
312  	 *
313  	 * This will result in a temporary fsal_export being created, and built into
314  	 * a stacked export.
315  	 *
316  	 * On entry, op_ctx has the original gsh_export and no fsal_export.
317  	 *
318  	 * The caller passes the original fsal_export, as well as the new super_export's
319  	 * FSAL when there is a stacked export. This will allow the underlying export to
320  	 * validate that the stacking has not changed.
321  	 *
322  	 * This function does not actually create a new fsal_export, the only purpose is
323  	 * to validate and update the config.
324  	 *
325  	 * @param[in]     fsal_hdl         FSAL module
326  	 * @param[in]     parse_node       opaque pointer to parse tree node for
327  	 *                                 export options to be passed to
328  	 *                                 load_config_from_node
329  	 * @param[out]    err_type         config proocessing error reporting
330  	 * @param[in]     original         The original export that is being updated
331  	 * @param[in]     updated_super    The updated super_export's FSAL
332  	 *
333  	 * @return FSAL status.
334  	 */
335  	
336  	fsal_status_t mem_update_export(struct fsal_module *fsal_hdl,
337  					void *parse_node,
338  					struct config_error_type *err_type,
339  					struct fsal_export *original,
340  					struct fsal_module *updated_super)
341  	{
342  		struct mem_fsal_export myself;
343  		int retval = 0;
344  		struct mem_fsal_export *orig =
345  			container_of(original, struct mem_fsal_export, export);
346  		fsal_status_t status;
347  	
348  		/* Check for changes in stacking by calling default update_export. */
349  		status = update_export(fsal_hdl, parse_node, err_type,
350  				       original, updated_super);
351  	
352  		if (FSAL_IS_ERROR(status))
353  			return status;
354  	
355  		memset(&myself, 0, sizeof(myself));
356  	
357  		retval = load_config_from_node(parse_node,
358  					       &mem_export_param_block,
359  					       &myself,
360  					       true,
361  					       err_type);
362  	
363  		if (retval != 0) {
364  			return posix2fsal_status(EINVAL);
365  		}
366  	
367  		/* Update the async parameters */
368  		atomic_store_uint32_t(&orig->async_delay, myself.async_delay);
369  		atomic_store_uint32_t(&orig->async_stall_delay,
370  				      myself.async_stall_delay);
371  		atomic_store_uint32_t(&orig->async_type, myself.async_type);
372  	
373  		LogEvent(COMPONENT_FSAL,
374  			 "Updated FSAL_MEM aync parameters type=%s, delay=%"PRIu32
375  			 ", stall_delay=%"PRIu32,
376  			 str_async_type(myself.async_type),
377  			 myself.async_delay, myself.async_stall_delay);
378  	
379  		return fsalstat(ERR_FSAL_NO_ERROR, 0);
380  	}
381