1    	/*
2    	 *
3    	 *
4    	 *
5    	 * Copyright CEA/DAM/DIF  (2008)
6    	 * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
7    	 *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
8    	 *
9    	 *
10   	 * This program is free software; you can redistribute it and/or
11   	 * modify it under the terms of the GNU Lesser General Public
12   	 * License as published by the Free Software Foundation; either
13   	 * version 3 of the License, or (at your option) any later version.
14   	 *
15   	 * This program is distributed in the hope that it will be useful,
16   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18   	 * Lesser General Public License for more details.
19   	 *
20   	 * You should have received a copy of the GNU Lesser General Public
21   	 * License along with this library; if not, write to the Free Software
22   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23   	 *
24   	 * ---------------------------------------
25   	 */
26   	
27   	/**
28   	 * @defgroup FSAL File-System Abstraction Layer
29   	 * @{
30   	 */
31   	
32   	/**
33   	 * @file  fsal.h
34   	 * @brief Main FSAL externs and functions
35   	 * @note  not called by other header files.
36   	 */
37   	
38   	/**
39   	 * @brief Thread Local Storage (TLS).
40   	 *
41   	 * TLS variables look like globals but since they are global only in the
42   	 * context of a single thread, they do not require locks.  This is true
43   	 * of all thread either within or separate from a/the fridge.
44   	 *
45   	 * All thread local storage is declared extern here.  The actual
46   	 * storage declaration is in fridgethr.c.
47   	 */
48   	
49   	/**
50   	 * @brief Operation context (op_ctx).
51   	 *
52   	 * This carries everything relevant to a protocol operation.
53   	 * Space for the struct itself is allocated elsewhere.
54   	 * Test/assert opctx != NULL first (or let the SEGV kill you)
55   	 */
56   	
57   	extern __thread struct req_op_context *op_ctx;
58   	
59   	#ifndef FSAL_H
60   	#define FSAL_H
61   	
(1) Event include_recursion: #include file "/home/kkeithle/src/github/nfs-ganesha/src/include/fsal_api.h" includes itself: fsal_api.h -> export_mgr.h -> fsal.h -> fsal_api.h
(2) Event caretline: ^
62   	#include "fsal_api.h"
63   	#include "nfs23.h"
64   	#include "nfs4_acls.h"
65   	#include "nfs4_fs_locations.h"
66   	
67   	/**
68   	 * @brief If we don't know how big a buffer we want for a link, use
69   	 * this value.
70   	 */
71   	
72   	#define fsal_default_linksize (4096)
73   	
74   	/**
75   	 * @brief Pointer to FSAL module by number.
76   	 * This is actually defined in common_pnfs.c
77   	 */
78   	extern struct fsal_module *pnfs_fsal[];
79   	
80   	/**
81   	 * @brief Delegations types list for the Delegations parameter in FSAL.
82   	 * This is actually defined in exports.c
83   	 */
84   	extern struct config_item_list deleg_types[];
85   	
86   	/* Export permissions for root op context, defined in protocol layer */
87   	extern uint32_t root_op_export_options;
88   	extern uint32_t root_op_export_set;
89   	
90   	/**
91   	 * @brief node id used to construct recovery directory in
92   	 * cluster implementation.
93   	 */
94   	extern int g_nodeid;
95   	
96   	/**
97   	 * @brief Ops context for asynch and not protocol tasks that need to use
98   	 * subsystems that depend on op_ctx.
99   	 */
100  	
101  	struct root_op_context {
102  		struct req_op_context req_ctx;
103  		struct req_op_context *old_op_ctx;
104  		struct user_cred creds;
105  		struct export_perms export_perms;
106  	};
107  	
108  	extern size_t open_fd_count;
109  	
110  	static inline void init_root_op_context(struct root_op_context *ctx,
111  						struct gsh_export *exp,
112  						struct fsal_export *fsal_exp,
113  						uint32_t nfs_vers,
114  						uint32_t nfs_minorvers,
115  						uint32_t req_type)
116  	{
117  		/* Initialize req_ctx.
118  		 * Note that a zeroed creds works just fine as root creds.
119  		 */
120  		memset(ctx, 0, sizeof(*ctx));
121  		ctx->req_ctx.creds = &ctx->creds;
122  		ctx->req_ctx.nfs_vers = nfs_vers;
123  		ctx->req_ctx.nfs_minorvers = nfs_minorvers;
124  		ctx->req_ctx.req_type = req_type;
125  	
126  		ctx->req_ctx.ctx_export = exp;
127  		ctx->req_ctx.fsal_export = fsal_exp;
128  		if (fsal_exp)
129  			ctx->req_ctx.fsal_module = fsal_exp->fsal;
130  		else if (op_ctx)
131  			ctx->req_ctx.fsal_module = op_ctx->fsal_module;
132  	
133  		ctx->req_ctx.export_perms = &ctx->export_perms;
134  		ctx->export_perms.set = root_op_export_set;
135  		ctx->export_perms.options = root_op_export_options;
136  	
137  		ctx->old_op_ctx = op_ctx;
138  		op_ctx = &ctx->req_ctx;
139  	}
140  	
141  	static inline void release_root_op_context(void)
142  	{
143  		struct root_op_context *ctx;
144  	
145  		ctx = container_of(op_ctx, struct root_op_context, req_ctx);
146  		op_ctx = ctx->old_op_ctx;
147  	}
148  	
149  	/******************************************************
150  	 *                Structure used to define a fsal
151  	 ******************************************************/
152  	
153  	#include "FSAL/access_check.h"	/* rethink where this should go */
154  	
155  	/**
156  	 * Global fsal manager functions
157  	 * used by nfs_main to initialize fsal modules.
158  	 */
159  	
160  	/* Called only within MODULE_INIT and MODULE_FINI functions of a fsal
161  	 * module
162  	 */
163  	
164  	/**
165  	 * @brief Register a FSAL
166  	 *
167  	 * This function registers an FSAL with ganesha and initializes the
168  	 * public portion of the FSAL data structure, including providing
169  	 * default operation vectors.
170  	 *
171  	 * @param[in,out] fsal_hdl      The FSAL module to register.
172  	 * @param[in]     name          The FSAL's name
173  	 * @param[in]     major_version Major version fo the API against which
174  	 *                              the FSAL was written
175  	 * @param[in]     minor_version Minor version of the API against which
176  	 *                              the FSAL was written.
177  	 *
178  	 * @return 0 on success.
179  	 * @return EINVAL on version mismatch.
180  	 */
181  	
182  	int register_fsal(struct fsal_module *fsal_hdl, const char *name,
183  			  uint32_t major_version, uint32_t minor_version,
184  			  uint8_t fsal_id);
185  	/**
186  	 * @brief Unregister an FSAL
187  	 *
188  	 * This function unregisters an FSAL from Ganesha.  It should be
189  	 * called from the module finalizer as part of unloading.
190  	 *
191  	 * @param[in] fsal_hdl The FSAL to unregister
192  	 *
193  	 * @return 0 on success.
194  	 * @return EBUSY if outstanding references or exports exist.
195  	 */
196  	
197  	int unregister_fsal(struct fsal_module *fsal_hdl);
198  	
199  	/**
200  	 * @brief Find and take a reference on an FSAL
201  	 *
202  	 * This function finds an FSAL by name and increments its reference
203  	 * count.  It is used as part of export setup.  The @c put method
204  	 * should be used  to release the reference before unloading.
205  	 */
206  	struct fsal_module *lookup_fsal(const char *name);
207  	
208  	int load_fsal(const char *name,
209  		      struct fsal_module **fsal_hdl);
210  	
211  	int fsal_load_init(void *node, const char *name,
212  			   struct fsal_module **fsal_hdl_p,
213  			   struct config_error_type *err_type);
214  	
215  	struct fsal_args {
216  		char *name;
217  	};
218  	
219  	void *fsal_init(void *link_mem, void *self_struct);
220  	
221  	struct subfsal_args {
222  		char *name;
223  		void *fsal_node;
224  	};
225  	
226  	int subfsal_commit(void *node, void *link_mem, void *self_struct,
227  			   struct config_error_type *err_type);
228  	
229  	void destroy_fsals(void);
230  	void emergency_cleanup_fsals(void);
231  	void start_fsals(void);
232  	
233  	void display_fsinfo(struct fsal_module *fsal);
234  	
235  	int display_attrlist(struct display_buffer *dspbuf,
236  			     struct attrlist *attr, bool is_obj);
237  	
238  	void log_attrlist(log_components_t component, log_levels_t level,
239  			  const char *reason, struct attrlist *attr, bool is_obj,
240  			  char *file, int line, char *function);
241  	
242  	#define LogAttrlist(component, level, reason, attr, is_obj)                  \
243  		do {                                                                 \
244  			if (unlikely(isLevel(component, level)))                     \
245  				log_attrlist(component, level, reason, attr, is_obj, \
246  					     (char *) __FILE__, __LINE__,            \
247  					     (char *) __func__);                     \
248  		} while (0)
249  	
250  	const char *msg_fsal_err(fsal_errors_t fsal_err);
251  	#define fsal_err_txt(s) msg_fsal_err((s).major)
252  	
253  	/*
254  	 * FSAL helpers
255  	 */
256  	
257  	enum cb_state {
258  		CB_ORIGINAL,
259  		CB_JUNCTION,
260  		CB_PROBLEM,
261  	};
262  	
263  	typedef fsal_errors_t (*helper_readdir_cb)
264  		(void *opaque,
265  		 struct fsal_obj_handle *obj,
266  		 const struct attrlist *attr,
267  		 uint64_t mounted_on_fileid,
268  		 uint64_t cookie,
269  		 enum cb_state cb_state);
270  	
271  	/**
272  	 * @brief Type of callback for fsal_readdir
273  	 *
274  	 * This callback provides the upper level protocol handling function
275  	 * with one directory entry at a time.  It may use the opaque to keep
276  	 * track of the structure it is filling, space used, and so forth.
277  	 *
278  	 * This function should return true if the entry has been added to the
279  	 * caller's responde, or false if the structure is fulled and the
280  	 * structure has not been added.
281  	 */
282  	
283  	struct fsal_readdir_cb_parms {
284  		void *opaque;		/*< Protocol specific parms */
285  		const char *name;	/*< Dir entry name */
286  		bool attr_allowed;	/*< True if caller has perm to getattr */
287  		bool in_result;		/*< true if the entry has been added to the
288  					 *< caller's responde, or false if the
289  					 *< structure is filled and the entry has not
290  					 *< been added. */
291  	};
292  	
293  	fsal_status_t fsal_setattr(struct fsal_obj_handle *obj, bool bypass,
294  				   struct state_t *state, struct attrlist *attr);
295  	
296  	/**
297  	 *
298  	 * @brief Checks the permissions on an object
299  	 *
300  	 * This function returns success if the supplied credentials possess
301  	 * permission required to meet the specified access.
302  	 *
303  	 * @param[in]  obj         The object to be checked
304  	 * @param[in]  access_type The kind of access to be checked
305  	 *
306  	 * @return FSAL status
307  	 *
308  	 */
309  	static inline
310  	fsal_status_t fsal_access(struct fsal_obj_handle *obj,
311  				  fsal_accessflags_t access_type)
312  	{
313  		return
314  		    obj->obj_ops->test_access(obj, access_type, NULL, NULL, false);
315  	}
316  	
317  	fsal_status_t fsal_link(struct fsal_obj_handle *obj,
318  				struct fsal_obj_handle *dest_dir,
319  				const char *name);
320  	fsal_status_t fsal_readlink(struct fsal_obj_handle *obj,
321  				    struct gsh_buffdesc *link_content);
322  	fsal_status_t fsal_lookup(struct fsal_obj_handle *parent,
323  				  const char *name,
324  				  struct fsal_obj_handle **obj,
325  				  struct attrlist *attrs_out);
326  	fsal_status_t fsal_lookupp(struct fsal_obj_handle *obj,
327  				   struct fsal_obj_handle **parent,
328  				   struct attrlist *attrs_out);
329  	fsal_status_t fsal_create(struct fsal_obj_handle *parent,
330  				  const char *name,
331  				  object_file_type_t type,
332  				  struct attrlist *attrs,
333  				  const char *link_content,
334  				  struct fsal_obj_handle **obj,
335  				  struct attrlist *attrs_out);
336  	void fsal_create_set_verifier(struct attrlist *sattr, uint32_t verf_hi,
337  				      uint32_t verf_lo);
338  	bool fsal_create_verify(struct fsal_obj_handle *obj, uint32_t verf_hi,
339  				uint32_t verf_lo);
340  	
341  	fsal_status_t fsal_readdir(struct fsal_obj_handle *directory, uint64_t cookie,
342  				   unsigned int *nbfound, bool *eod_met,
343  				   attrmask_t attrmask, helper_readdir_cb cb,
344  				   void *opaque);
345  	fsal_status_t fsal_remove(struct fsal_obj_handle *parent, const char *name);
346  	fsal_status_t fsal_rename(struct fsal_obj_handle *dir_src,
347  				  const char *oldname,
348  				  struct fsal_obj_handle *dir_dest,
349  				  const char *newname);
350  	fsal_status_t fsal_open2(struct fsal_obj_handle *in_obj,
351  				 struct state_t *state,
352  				 fsal_openflags_t openflags,
353  				 enum fsal_create_mode createmode,
354  				 const char *name,
355  				 struct attrlist *attr,
356  				 fsal_verifier_t verifier,
357  				 struct fsal_obj_handle **obj,
358  				 struct attrlist *attrs_out);
359  	fsal_status_t fsal_reopen2(struct fsal_obj_handle *obj,
360  				   struct state_t *state,
361  				   fsal_openflags_t openflags,
362  				   bool check_permission);
363  	fsal_status_t get_optional_attrs(struct fsal_obj_handle *obj_hdl,
364  					 struct attrlist *attrs_out);
365  	/**
366  	 * @brief Close a file
367  	 *
368  	 * This handles both support_ex case and regular case (in case of
369  	 * support_ex, close method is expected to manage whether file is
370  	 * actually open or not, in old API case, close method should only
371  	 * be closed if the file is open).
372  	 *
373  	 * In a change to the old way, non-regular files are just ignored.
374  	 *
375  	 * @param[in] obj	File to close
376  	 * @return FSAL status
377  	 */
378  	static inline fsal_status_t fsal_close(struct fsal_obj_handle *obj_hdl)
379  	{
380  		if (obj_hdl->type != REGULAR_FILE) {
381  			/* Can only close a regular file */
382  			return fsalstat(ERR_FSAL_NO_ERROR, 0);
383  		}
384  	
385  		/* Return the result of close method. */
386  		fsal_status_t status = obj_hdl->obj_ops->close(obj_hdl);
387  	
388  		if (status.major != ERR_FSAL_NOT_OPENED) {
389  			ssize_t count;
390  	
391  			count = atomic_dec_size_t(&open_fd_count);
392  			if (count < 0) {
393  				LogCrit(COMPONENT_FSAL,
394  					"open_fd_count is negative: %zd", count);
395  			}
396  		} else {
397  			/* Wasn't open.  Not an error, but shouldn't decrement */
398  			status = fsalstat(ERR_FSAL_NO_ERROR, 0);
399  		}
400  	
401  		return status;
402  	}
403  	
404  	fsal_status_t fsal_statfs(struct fsal_obj_handle *obj,
405  				  fsal_dynamicfsinfo_t *dynamicinfo);
406  	
407  	/**
408  	 * @brief Commit a section of a file to storage
409  	 *
410  	 * @param[in] obj	File to commit
411  	 * @param[in] offset	Offset for start of commit
412  	 * @param[in] len	Length of commit
413  	 * @return FSAL status
414  	 */
415  	static inline
416  	fsal_status_t fsal_commit(struct fsal_obj_handle *obj, off_t offset,
417  				 size_t len)
418  	{
419  		if ((uint64_t) len > ~(uint64_t) offset)
420  			return fsalstat(ERR_FSAL_INVAL, 0);
421  	
422  		return obj->obj_ops->commit2(obj, offset, len);
423  	}
424  	fsal_status_t fsal_verify2(struct fsal_obj_handle *obj,
425  				   fsal_verifier_t verifier);
426  	
427  	/**
428  	 * @brief Pepare an attrlist for fetching attributes.
429  	 *
430  	 * @param[in,out] attrs   The attrlist to work with
431  	 * @param[in]             The mask to use for the fetch
432  	 *
433  	 */
434  	
435  	static inline void fsal_prepare_attrs(struct attrlist *attrs,
436  					      attrmask_t request_mask)
437  	{
438  		memset(attrs, 0, sizeof(*attrs));
439  		attrs->request_mask = request_mask;
440  	}
441  	
442  	/**
443  	 * @brief Release any extra resources from an attrlist.
444  	 *
445  	 * @param[in] attrs   The attrlist to work with
446  	 *
447  	 */
448  	
449  	static inline void fsal_release_attrs(struct attrlist *attrs)
450  	{
451  		if (attrs->acl != NULL) {
452  			int acl_status;
453  	
454  			acl_status = nfs4_acl_release_entry(attrs->acl);
455  	
456  			if (acl_status != NFS_V4_ACL_SUCCESS)
457  				LogCrit(COMPONENT_FSAL,
458  					"Failed to release old acl, status=%d",
459  					acl_status);
460  	
461  			/* Poison the acl since we no longer hold a reference. */
462  			attrs->acl = NULL;
463  			attrs->valid_mask &= ~ATTR_ACL;
464  		}
465  	
466  		if (attrs->fs_locations) {
467  			nfs4_fs_locations_release(attrs->fs_locations);
468  			attrs->fs_locations = NULL;
469  			attrs->valid_mask &= ~ATTR4_FS_LOCATIONS;
470  		}
471  	
472  		attrs->sec_label.slai_data.slai_data_len = 0;
473  		gsh_free(attrs->sec_label.slai_data.slai_data_val);
474  		attrs->sec_label.slai_data.slai_data_val = NULL;
475  	}
476  	
477  	/**
478  	 * @brief Copy a set of attributes
479  	 *
480  	 * If ACL is requested in dest->request_mask, then ACL reference is acquired,
481  	 * otherwise acl pointer is set to NULL.
482  	 *
483  	 * @param[in,out] dest       The attrlist to receive the copy (mask must be set)
484  	 * @param[in]     src        The attrlist to make a copy of
485  	 * @param[in]     pass_refs  If true, pass the ACL reference to dest.
486  	 *
487  	 */
488  	
489  	static inline void fsal_copy_attrs(struct attrlist *dest,
490  					   struct attrlist *src,
491  					   bool pass_refs)
492  	{
493  		attrmask_t save_request_mask = dest->request_mask;
494  	
495  		/* Copy source to dest, but retain dest->request_mask */
496  		*dest = *src;
497  		dest->request_mask = save_request_mask;
498  	
499  		if (pass_refs && ((save_request_mask & ATTR_ACL) != 0)) {
500  			/* Pass any ACL reference to the dest, so remove from
501  			 * src without adjusting the refcount.
502  			 */
503  			src->acl = NULL;
504  			src->valid_mask &= ~ATTR_ACL;
505  		} else if (dest->acl != NULL && ((save_request_mask & ATTR_ACL) != 0)) {
506  			/* Take reference on ACL if necessary */
507  			nfs4_acl_entry_inc_ref(dest->acl);
508  		} else {
509  			/* Make sure acl is NULL and don't pass a ref back (so
510  			 * caller when calling fsal_release_attrs will not have to
511  			 * release the ACL reference).
512  			 */
513  			dest->acl = NULL;
514  			dest->valid_mask &= ~ATTR_ACL;
515  		}
516  	
517  		if (pass_refs && ((save_request_mask & ATTR4_FS_LOCATIONS) != 0)) {
518  			src->fs_locations = NULL;
519  			src->valid_mask &= ~ATTR4_FS_LOCATIONS;
520  		} else if (dest->fs_locations != NULL &&
521  			((save_request_mask & ATTR4_FS_LOCATIONS) != 0)) {
522  			nfs4_fs_locations_get_ref(dest->fs_locations);
523  		} else {
524  			dest->fs_locations = NULL;
525  			dest->valid_mask &= ~ATTR4_FS_LOCATIONS;
526  		}
527  	
528  		/*
529  		 * Ditto for security label. Here though, we just make a copy if
530  		 * needed.
531  		 */
532  		if (pass_refs && ((save_request_mask & ATTR4_SEC_LABEL) != 0)) {
533  			src->sec_label.slai_data.slai_data_len = 0;
534  			src->sec_label.slai_data.slai_data_val = NULL;
535  			src->valid_mask &= ~ATTR4_SEC_LABEL;
536  		} else if (dest->sec_label.slai_data.slai_data_val != NULL &&
537  			((save_request_mask & ATTR4_SEC_LABEL) != 0)) {
538  			dest->sec_label.slai_data.slai_data_val = (char *)
539  				gsh_memdup(dest->sec_label.slai_data.slai_data_val,
540  					   dest->sec_label.slai_data.slai_data_len);
541  		} else {
542  			dest->sec_label.slai_data.slai_data_len = 0;
543  			dest->sec_label.slai_data.slai_data_val = NULL;
544  			dest->valid_mask &= ~ATTR4_SEC_LABEL;
545  		}
546  	}
547  	
548  	/**
549  	 * @brief Return a changeid4 for this file.
550  	 *
551  	 * @param[in] obj   The file to query.
552  	 *
553  	 * @return A changeid4 indicating the last modification of the file.
554  	 */
555  	
556  	static inline changeid4
557  	fsal_get_changeid4(struct fsal_obj_handle *obj)
558  	{
559  		struct attrlist attrs;
560  		fsal_status_t status;
561  		changeid4 change;
562  	
563  		fsal_prepare_attrs(&attrs, ATTR_CHANGE);
564  	
565  		status = obj->obj_ops->getattrs(obj, &attrs);
566  	
567  		if (FSAL_IS_ERROR(status))
568  			return 0;
569  	
570  		change = (changeid4) attrs.change;
571  	
572  		/* Done with the attrs */
573  		fsal_release_attrs(&attrs);
574  	
575  		return change;
576  	}
577  	
578  	static inline
579  	enum fsal_create_mode nfs4_createmode_to_fsal(createmode4 createmode)
580  	{
581  		return (enum fsal_create_mode) (1 + (unsigned int) createmode);
582  	}
583  	
584  	static inline
585  	enum fsal_create_mode nfs3_createmode_to_fsal(createmode3 createmode)
586  	{
587  		return (enum fsal_create_mode) (1 + (unsigned int) createmode);
588  	}
589  	
590  	/**
591  	 * @brief Determine if the openflags associated with an fd indicate it
592  	 * is not open in a mode usable by the caller.
593  	 *
594  	 * The caller may pass FSAL_O_ANY to indicate any mode of open (RDONLY,
595  	 * WRONLY, or RDWR is useable - often just to fetch attributes or something).
596  	 *
597  	 * @param[in] fd_openflags The openflags describing the fd
598  	 * @param[in] to_openflags The openflags describing the desired mode
599  	 */
600  	
601  	static inline bool not_open_usable(fsal_openflags_t fd_openflags,
602  					   fsal_openflags_t to_openflags)
603  	{
604  		/* 1. fd_openflags will NEVER be FSAL_O_ANY.
605  		 * 2. If to_openflags == FSAL_O_ANY, the first half will be true if the
606  		 *    file is closed, and the second half MUST be true (per statement 1)
607  		 * 3. If to_openflags is anything else, the first half will be true and
608  		 *    the second half will be true if fd_openflags does not include
609  		 *    the requested modes.
610  		 */
611  		return (to_openflags != FSAL_O_ANY || fd_openflags == FSAL_O_CLOSED)
612  		       && ((fd_openflags & to_openflags) != to_openflags);
613  	}
614  	
615  	/**
616  	 * @brief Determine if the openflags associated with an fd indicate it
617  	 * is open in a mode usable by the caller.
618  	 *
619  	 * The caller may pass FSAL_O_ANY to indicate any mode of open (RDONLY,
620  	 * WRONLY, or RDWR is useable - often just to fetch attributes or something).
621  	 *
622  	 * Note that this function is not just an inversion of the above function
623  	 * because O_SYNC is not considered.
624  	 *
625  	 * @param[in] fd_openflags The openflags describing the fd
626  	 * @param[in] to_openflags The openflags describing the desired mode
627  	 */
628  	
629  	static inline bool open_correct(fsal_openflags_t fd_openflags,
630  					fsal_openflags_t to_openflags)
631  	{
632  		return (to_openflags == FSAL_O_ANY && fd_openflags != FSAL_O_CLOSED)
633  		       || (to_openflags != FSAL_O_ANY
634  			   && (fd_openflags & to_openflags & FSAL_O_RDWR)
635  						== (to_openflags & FSAL_O_RDWR));
636  	}
637  	
638  	/**
639  	 * @brief "fsal_op_stats" struct useful for all the fsals which are going to
640  	 * implement support for FSAL specific statistics
641  	 */
642  	struct fsal_op_stats {
643  		uint16_t op_code;
644  		uint64_t resp_time;
645  		uint64_t num_ops;
646  		uint64_t resp_time_max;
647  		uint64_t resp_time_min;
648  	};
649  	
650  	struct fsal_stats {
651  		uint16_t total_ops;
652  		struct fsal_op_stats *op_stats;
653  	};
654  	
655  	/* Async Processes that will be made synchronous */
656  	struct async_process_data {
657  		/** Return from process */
658  		fsal_status_t ret;
659  		/** Indicator callback is done. */
660  		bool done;
661  		/** Mutex to protect done and condition variable. */
662  		pthread_mutex_t *mutex;
663  		/** Condition variable to signal callback is done. */
664  		pthread_cond_t *cond;
665  	};
666  	
667  	extern void fsal_read(struct fsal_obj_handle *obj_hdl,
668  			      bool bypass,
669  			      struct fsal_io_arg *arg,
670  			      struct async_process_data *data);
671  	
672  	extern void fsal_write(struct fsal_obj_handle *obj_hdl,
673  			       bool bypass,
674  			       struct fsal_io_arg *arg,
675  			       struct async_process_data *data);
676  	
677  	#endif				/* !FSAL_H */
678  	/** @} */
679