1    	/*
2    	 * vim:noexpandtab:shiftwidth=8:tabstop=8:
3    	 *
4    	 * Copyright © 2017, Red Hat, Inc.
5    	 * Author: Daniel Gryniewicz <dang@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 License
9    	 * as published by the Free Software Foundation; either version 3 of
10   	 * the License, or (at your option) any later version.
11   	 *
12   	 * This program is distributed in the hope that it will be useful, but
13   	 * 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
20   	 * 02110-1301 USA
21   	 *
22   	 * -------------
23   	 */
24   	
25   	/**
26   	 * @file   FSAL_MEM/mem_up.c
27   	 * @author Daniel Gryniewicz <dang@redhat.com>
28   	 *
29   	 * @brief Upcalls
30   	 *
31   	 * Implement upcalls for testing purposes
32   	 */
33   	
34   	#include "config.h"
35   	#include <fcntl.h>
36   	#include <stdlib.h>
37   	#include "fsal.h"
38   	#include "fsal_convert.h"
39   	#include "mem_int.h"
40   	
41   	static struct fridgethr *mem_up_fridge;
42   	
43   	/**
44   	 * @brief Invalidate an object
45   	 *
46   	 * This function sends an invalidate for an object.  The object itself is not
47   	 * really deleted, since there's no way to get it back, but it should allow
48   	 * testing of the invalidate UP call.
49   	 *
50   	 * @param[in] mfe	MEM export owning handle
51   	 * @param[in] hdl	Handle to invalidate
52   	 */
53   	static void
54   	mem_invalidate(struct mem_fsal_export *mfe, struct mem_fsal_obj_handle *hdl)
55   	{
56   		const struct fsal_up_vector *up_ops = mfe->export.up_ops;
57   		fsal_status_t status;
58   		struct gsh_buffdesc fh_desc;
59   	
60   		LogFullDebug(COMPONENT_FSAL_UP, "invalidating %s", hdl->m_name);
61   	
62   		hdl->obj_handle.obj_ops->handle_to_key(&hdl->obj_handle, &fh_desc);
63   	
64   		status = up_ops->invalidate(up_ops, &fh_desc, FSAL_UP_INVALIDATE_CACHE);
65   		if (FSAL_IS_ERROR(status)) {
66   			LogMajor(COMPONENT_FSAL_UP, "error invalidating %s: %s",
67   				 hdl->m_name, fsal_err_txt(status));
68   		}
69   	}
70   	
71   	/**
72   	 * @brief Invalidate and close an object
73   	 *
74   	 * This function sends an invalidate_close for an object.  The object itself is
75   	 * not really deleted, since there's no way to get it back, but it should allow
76   	 * testing of the invalidate_close UP call.
77   	 *
78   	 * @param[in] mfe	MEM export owning handle
79   	 * @param[in] hdl	Handle to invalidate
80   	 */
81   	static void
82   	mem_invalidate_close(struct mem_fsal_export *mfe,
83   			     struct mem_fsal_obj_handle *hdl)
84   	{
85   		const struct fsal_up_vector *up_ops = mfe->export.up_ops;
86   		fsal_status_t status;
87   		struct gsh_buffdesc fh_desc;
88   	
89   		LogFullDebug(COMPONENT_FSAL_UP, "invalidate_closing %s", hdl->m_name);
90   	
91   		hdl->obj_handle.obj_ops->handle_to_key(&hdl->obj_handle, &fh_desc);
92   	
93   		status = up_ops->invalidate_close(up_ops, &fh_desc,
94   						  FSAL_UP_INVALIDATE_CACHE);
95   		if (FSAL_IS_ERROR(status)) {
96   			LogMajor(COMPONENT_FSAL_UP, "error invalidate_closing %s: %s",
97   				 hdl->m_name, fsal_err_txt(status));
98   		}
99   	}
100  	
101  	/**
102  	 * @brief Update an object
103  	 *
104  	 * This function sends an update for an object.  In this case, we update some of
105  	 * the times, just so something changed.
106  	 *
107  	 * @param[in] mfe	MEM export owning handle
108  	 * @param[in] hdl	Handle to update
109  	 */
110  	static void
111  	mem_update(struct mem_fsal_export *mfe, struct mem_fsal_obj_handle *hdl)
112  	{
113  		const struct fsal_up_vector *up_ops = mfe->export.up_ops;
114  		fsal_status_t status;
115  		struct gsh_buffdesc fh_desc;
116  		struct attrlist attrs;
117  	
118  		LogFullDebug(COMPONENT_FSAL_UP, "updating %s", hdl->m_name);
119  	
120  		hdl->obj_handle.obj_ops->handle_to_key(&hdl->obj_handle, &fh_desc);
121  	
122  		fsal_prepare_attrs(&attrs, 0);
123  		/* Set CTIME */
124  		now(&hdl->attrs.ctime);
125  		attrs.ctime = hdl->attrs.ctime; /* struct copy */
126  		FSAL_SET_MASK(attrs.valid_mask, ATTR_CTIME);
127  	
128  		/* Set change */
129  		hdl->attrs.change = timespec_to_nsecs(&hdl->attrs.ctime);
130  		attrs.change = hdl->attrs.change;
131  		FSAL_SET_MASK(attrs.valid_mask, ATTR_CHANGE);
132  	
133  		status = up_ops->update(up_ops, &fh_desc, &attrs, fsal_up_update_null);
134  		if (FSAL_IS_ERROR(status)) {
135  			LogMajor(COMPONENT_FSAL_UP, "error updating %s: %s",
136  				 hdl->m_name, fsal_err_txt(status));
137  		}
138  	}
139  	
140  	/**
141  	 * @brief Select a random obj from an export
142  	 *
143  	 * @param[in] mfe	Export to select from
144  	 * @return Obj on success, NULL on failure
145  	 */
146  	struct mem_fsal_obj_handle *
147  	mem_rand_obj(struct mem_fsal_export *mfe)
148  	{
149  		struct mem_fsal_obj_handle *res = NULL;
150  		struct glist_head *glist, *glistn;
151  		uint32_t n = 2;
152  	
153  		if (glist_empty(&mfe->mfe_objs))
154  			return NULL;
155  	
156  		PTHREAD_RWLOCK_rdlock(&mfe->mfe_exp_lock);
157  		glist_for_each_safe(glist, glistn, &mfe->mfe_objs) {
158  			if (res == NULL) {
159  				/* Grab first entry */
160  				res = glist_entry(glist, struct mem_fsal_obj_handle,
161  						  mfo_exp_entry);
162  				continue;
163  			}
164  	
(1) Event dont_call: "rand" should not be used for security-related applications, because linear congruential algorithms are too easy to break.
(2) Event remediation: Use a compliant random number generator, such as "/dev/random" or "/dev/urandom" on Unix-like systems, and CNG (Cryptography API: Next Generation) on Windows.
165  			if (rand() % n == 0) {
166  				/* Replace with current */
167  				res = glist_entry(glist, struct mem_fsal_obj_handle,
168  						  mfo_exp_entry);
169  				break;
170  			}
171  			n++;
172  		}
173  		PTHREAD_RWLOCK_unlock(&mfe->mfe_exp_lock);
174  	
175  		return res;
176  	}
177  	
178  	/**
179  	 * @brief Run an iteration of the UP call thread
180  	 *
181  	 * Each iteration exercises various UP calls.
182  	 *
183  	 * - Pick a random obj in each export, and invalidate it
184  	 *
185  	 * @param[in] ctx	Thread context
186  	 * @return Return description
187  	 */
188  	static void
189  	mem_up_run(struct fridgethr_context *ctx)
190  	{
191  		struct glist_head *glist, *glistn;
192  	
193  		glist_for_each_safe(glist, glistn, &MEM.mem_exports) {
194  			struct mem_fsal_export *mfe;
195  			struct mem_fsal_obj_handle *hdl;
196  	
197  			mfe = glist_entry(glist, struct mem_fsal_export, export_entry);
198  	
199  			/* Update a handle */
200  			hdl = mem_rand_obj(mfe);
201  			if (hdl)
202  				mem_update(mfe, hdl);
203  	
204  			/* Invalidate a handle */
205  			hdl = mem_rand_obj(mfe);
206  			if (hdl)
207  				mem_invalidate(mfe, hdl);
208  	
209  			/* Invalidate and close a handle */
210  			hdl = mem_rand_obj(mfe);
211  			if (hdl)
212  				mem_invalidate_close(mfe, hdl);
213  		}
214  	}
215  	
216  	/**
217  	 * Initialize subsystem
218  	 */
219  	fsal_status_t
220  	mem_up_pkginit(void)
221  	{
222  		/* Return code from system calls */
223  		int code = 0;
224  		struct fridgethr_params frp;
225  	
226  		if (MEM.up_interval == 0) {
227  			/* Don't run up-thread */
228  			return fsalstat(ERR_FSAL_NO_ERROR, 0);
229  		}
230  	
231  		if (mem_up_fridge) {
232  			/* Already initialized */
233  			return fsalstat(ERR_FSAL_NO_ERROR, 0);
234  		}
235  	
236  		memset(&frp, 0, sizeof(struct fridgethr_params));
237  		frp.thr_max = 1;
238  		frp.thr_min = 1;
239  		frp.thread_delay = MEM.up_interval;
240  		frp.flavor = fridgethr_flavor_looper;
241  	
242  		/* spawn MEM_UP background thread */
243  		code = fridgethr_init(&mem_up_fridge, "MEM_UP_fridge", &frp);
244  		if (code != 0) {
245  			LogMajor(COMPONENT_FSAL_UP,
246  				 "Unable to initialize MEM_UP fridge, error code %d.",
247  				 code);
248  			return posix2fsal_status(code);
249  		}
250  	
251  		code = fridgethr_submit(mem_up_fridge, mem_up_run, NULL);
252  		if (code != 0) {
253  			LogMajor(COMPONENT_FSAL_UP,
254  				 "Unable to start MEM_UP thread, error code %d.", code);
255  			return fsalstat(posix2fsal_error(code), code);
256  		}
257  	
258  		return fsalstat(ERR_FSAL_NO_ERROR, 0);
259  	}
260  	
261  	/**
262  	 * Shutdown subsystem
263  	 *
264  	 * @return FSAL status
265  	 */
266  	fsal_status_t
267  	mem_up_pkgshutdown(void)
268  	{
269  		if (!mem_up_fridge) {
270  			/* Interval wasn't configured */
271  			return fsalstat(ERR_FSAL_NO_ERROR, 0);
272  		}
273  	
274  		int rc = fridgethr_sync_command(mem_up_fridge,
275  						fridgethr_comm_stop,
276  						120);
277  	
278  		if (rc == ETIMEDOUT) {
279  			LogMajor(COMPONENT_FSAL_UP,
280  				 "Shutdown timed out, cancelling threads.");
281  			fridgethr_cancel(mem_up_fridge);
282  		} else if (rc != 0) {
283  			LogMajor(COMPONENT_FSAL_UP,
284  				 "Failed shutting down MEM_UP thread: %d", rc);
285  		}
286  	
287  		fridgethr_destroy(mem_up_fridge);
288  		mem_up_fridge = NULL;
289  		return fsalstat(posix2fsal_error(rc), rc);
290  	}
291