1    	/*
2    	 * Copyright (C) Panasas Inc., 2011
3    	 * Author: Jim Lieb jlieb@panasas.com
4    	 *
5    	 * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
6    	 *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
7    	 *
8    	 *
9    	 * This program is free software; you can redistribute it and/or
10   	 * modify it under the terms of the GNU Lesser General Public
11   	 * License as published by the Free Software Foundation; either
12   	 * version 3 of the License, or (at your option) any later version.
13   	 *
14   	 * This program is distributed in the hope that it will be useful, but
15   	 * WITHOUT ANY WARRANTY; without even the implied warranty of
16   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   	 * Lesser General Public License for more details.
18   	 *
19   	 * You should have received a copy of the GNU Lesser General Public
20   	 * License along with this library; if not, write to the Free Software
21   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22   	 * 02110-1301 USA
23   	 *
24   	 * -------------
25   	 */
26   	
27   	/**
28   	 * @addtogroup FSAL
29   	 * @{
30   	 */
31   	
32   	/**
33   	 * @file fsal_commonlib.c
34   	 * @author Jim Lieb <jlieb@panasas.com>
35   	 * @brief Common functions for and private to FSAL modules.
36   	 *
37   	 * The prime requirement for functions to be here is that they operate only
38   	 * on the public part of the FSAL api and are therefore sharable by all fsal
39   	 * implementations.
40   	 */
41   	#include "config.h"
42   	
43   	#include <misc/queue.h> /* avoid conflicts with sys/queue.h */
44   	#ifdef LINUX
45   	#include <sys/sysmacros.h> /* for major(3), minor(3) */
46   	#endif
47   	#include <libgen.h>		/* used for 'dirname' */
48   	#include <pthread.h>
49   	#include <sys/stat.h>
50   	#include <unistd.h>
51   	#include <strings.h>
52   	#include <string.h>
53   	#include <fcntl.h>
54   	#include <sys/types.h>
55   	#include <sys/statvfs.h>
56   	#if __FreeBSD__
57   	#include <sys/mount.h>
58   	#else
59   	#include <sys/vfs.h>
60   	#endif
61   	#include <os/quota.h>
62   	
63   	#include "common_utils.h"
64   	#ifdef HAVE_MNTENT_H
65   	#include <mntent.h>
66   	#endif
67   	#include "gsh_config.h"
68   	#include "gsh_list.h"
69   	#ifdef USE_BLKID
70   	#include <blkid/blkid.h>
71   	#include <uuid/uuid.h>
72   	#endif
73   	#include "fsal.h"
74   	#include "fsal_api.h"
75   	#include "FSAL/fsal_commonlib.h"
76   	#include "FSAL/access_check.h"
77   	#include "fsal_private.h"
78   	#include "fsal_convert.h"
79   	#include "nfs4_acls.h"
80   	#include "sal_data.h"
81   	#include "nfs_init.h"
82   	#include "mdcache.h"
83   	#include "nfs_proto_tools.h"
84   	#ifdef USE_DBUS
85   	#include "gsh_dbus.h"
86   	#endif
87   	#include "server_stats_private.h"
88   	
89   	
90   	#ifdef USE_BLKID
91   	static struct blkid_struct_cache *cache;
92   	#endif
93   	
94   	/* fsal_attach_export
95   	 * called from the FSAL's create_export method with a reference on the fsal.
96   	 */
97   	
98   	int fsal_attach_export(struct fsal_module *fsal_hdl,
99   			       struct glist_head *obj_link)
100  	{
101  		int retval = 0;
102  	
103  		if (atomic_fetch_int32_t(&fsal_hdl->refcount) > 0) {
104  			glist_add(&fsal_hdl->exports, obj_link);
105  		} else {
106  			LogCrit(COMPONENT_CONFIG,
107  				"Attaching export with out holding a reference!. hdl= = 0x%p",
108  				fsal_hdl);
109  			retval = EINVAL;
110  		}
111  		return retval;
112  	}
113  	
114  	/* fsal_detach_export
115  	 * called by an export when it is releasing itself.
116  	 * does not require a reference to be taken.  The list has
117  	 * kept the fsal "busy".
118  	 */
119  	
120  	void fsal_detach_export(struct fsal_module *fsal_hdl,
121  				struct glist_head *obj_link)
122  	{
123  		PTHREAD_RWLOCK_wrlock(&fsal_hdl->lock);
124  		glist_del(obj_link);
125  		PTHREAD_RWLOCK_unlock(&fsal_hdl->lock);
126  	}
127  	
128  	/**
129  	 * @brief Initialize export ops vectors
130  	 *
131  	 * @param[in] exp Export handle
132  	 *
133  	 */
134  	
135  	void fsal_export_init(struct fsal_export *exp)
136  	{
137  		memcpy(&exp->exp_ops, &def_export_ops, sizeof(struct export_ops));
138  		exp->export_id = op_ctx->ctx_export->export_id;
139  	}
140  	
141  	/**
142  	 * @brief Stack an export on top of another
143  	 *
144  	 * Set up export stacking for stackable FSALs
145  	 *
146  	 * @param[in] sub_export	Export being stacked on
147  	 * @param[in] super_export	Export stacking on top
148  	 * @return Return description
149  	 */
150  	void fsal_export_stack(struct fsal_export *sub_export,
151  			       struct fsal_export *super_export)
152  	{
153  		sub_export->super_export = super_export;
154  		super_export->sub_export = sub_export;
155  	}
156  	
157  	/**
158  	 * @brief Free export ops vectors
159  	 *
160  	 * Free the memory allocated by init_export_ops. Poison pointers.
161  	 *
162  	 * @param[in] exp_hdl Export handle
163  	 *
164  	 */
165  	
166  	void free_export_ops(struct fsal_export *exp_hdl)
167  	{
168  		memset(&exp_hdl->exp_ops, 0, sizeof(exp_hdl->exp_ops));	/* poison */
169  	}
170  	
171  	/* fsal_export to fsal_obj_handle helpers
172  	 */
173  	
174  	void fsal_default_obj_ops_init(struct fsal_obj_ops *obj_ops)
175  	{
176  		*obj_ops = def_handle_ops;
177  	}
178  	
179  	void fsal_obj_handle_init(struct fsal_obj_handle *obj, struct fsal_export *exp,
180  				  object_file_type_t type)
181  	{
182  		pthread_rwlockattr_t attrs;
183  	
184  		obj->fsal = exp->fsal;
185  		obj->type = type;
186  		pthread_rwlockattr_init(&attrs);
187  	#ifdef GLIBC
188  		pthread_rwlockattr_setkind_np(
189  			&attrs,
190  			PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
191  	#endif
192  		PTHREAD_RWLOCK_init(&obj->obj_lock, &attrs);
193  	
194  		PTHREAD_RWLOCK_wrlock(&obj->fsal->lock);
195  		glist_add(&obj->fsal->handles, &obj->handles);
196  		PTHREAD_RWLOCK_unlock(&obj->fsal->lock);
197  	
198  		pthread_rwlockattr_destroy(&attrs);
199  	}
200  	
201  	void fsal_obj_handle_fini(struct fsal_obj_handle *obj)
202  	{
203  		PTHREAD_RWLOCK_wrlock(&obj->fsal->lock);
204  		glist_del(&obj->handles);
205  		PTHREAD_RWLOCK_unlock(&obj->fsal->lock);
206  		PTHREAD_RWLOCK_destroy(&obj->obj_lock);
207  		memset(&obj->obj_ops, 0, sizeof(obj->obj_ops));	/* poison myself */
208  		obj->fsal = NULL;
209  	}
210  	
211  	/* fsal_module to fsal_pnfs_ds helpers
212  	 */
213  	
214  	void fsal_pnfs_ds_init(struct fsal_pnfs_ds *pds, struct fsal_module *fsal)
215  	{
216  		pthread_rwlockattr_t attrs;
217  	
218  		pds->refcount = 1;	/* we start out with a reference */
219  		fsal->m_ops.fsal_pnfs_ds_ops(&pds->s_ops);
220  		pds->fsal = fsal;
221  	
222  		pthread_rwlockattr_init(&attrs);
223  	#ifdef GLIBC
224  		pthread_rwlockattr_setkind_np(
225  			&attrs,
226  			PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
227  	#endif
228  		PTHREAD_RWLOCK_init(&pds->lock, &attrs);
229  		glist_init(&pds->ds_handles);
230  	
231  		PTHREAD_RWLOCK_wrlock(&fsal->lock);
232  		glist_add(&fsal->servers, &pds->server);
233  		PTHREAD_RWLOCK_unlock(&fsal->lock);
234  	
235  		pthread_rwlockattr_destroy(&attrs);
236  	}
237  	
238  	void fsal_pnfs_ds_fini(struct fsal_pnfs_ds *pds)
239  	{
240  		PTHREAD_RWLOCK_wrlock(&pds->fsal->lock);
241  		glist_del(&pds->server);
242  		PTHREAD_RWLOCK_unlock(&pds->fsal->lock);
243  		PTHREAD_RWLOCK_destroy(&pds->lock);
244  		memset(&pds->s_ops, 0, sizeof(pds->s_ops));	/* poison myself */
245  		pds->fsal = NULL;
246  	}
247  	
248  	/* fsal_pnfs_ds to fsal_ds_handle helpers
249  	 */
250  	
251  	void fsal_ds_handle_init(struct fsal_ds_handle *dsh, struct fsal_pnfs_ds *pds)
252  	{
253  		dsh->refcount = 1;	/* we start out with a reference */
254  		pds->s_ops.fsal_dsh_ops(&dsh->dsh_ops);
255  		dsh->pds = pds;
256  	
257  		PTHREAD_RWLOCK_wrlock(&pds->lock);
258  		glist_add(&pds->ds_handles, &dsh->ds_handle);
259  		PTHREAD_RWLOCK_unlock(&pds->lock);
260  	}
261  	
262  	void fsal_ds_handle_fini(struct fsal_ds_handle *dsh)
263  	{
264  		PTHREAD_RWLOCK_wrlock(&dsh->pds->lock);
265  		glist_del(&dsh->ds_handle);
266  		PTHREAD_RWLOCK_unlock(&dsh->pds->lock);
267  	
268  		memset(&dsh->dsh_ops, 0, sizeof(dsh->dsh_ops));	/* poison myself */
269  		dsh->pds = NULL;
270  	}
271  	
272  	/**
273  	 * @brief FSAL error code to error message
274  	 *
275  	 * @param[in] fsal_err Error code
276  	 *
277  	 * @return Error message, empty string if not found.
278  	 */
279  	
280  	const char *msg_fsal_err(fsal_errors_t fsal_err)
281  	{
282  		switch (fsal_err) {
283  		case ERR_FSAL_NO_ERROR:
284  			return "No error";
285  		case ERR_FSAL_PERM:
286  			return "Forbidden action";
287  		case ERR_FSAL_NOENT:
288  			return "No such file or directory";
289  		case ERR_FSAL_IO:
290  			return "I/O error";
291  		case ERR_FSAL_NXIO:
292  			return "No such device or address";
293  		case ERR_FSAL_NOMEM:
294  			return "Not enough memory";
295  		case ERR_FSAL_ACCESS:
296  			return "Permission denied";
297  		case ERR_FSAL_FAULT:
298  			return "Bad address";
299  		case ERR_FSAL_EXIST:
300  			return "This object already exists";
301  		case ERR_FSAL_XDEV:
302  			return "This operation can't cross filesystems";
303  		case ERR_FSAL_NOTDIR:
304  			return "This object is not a directory";
305  		case ERR_FSAL_ISDIR:
306  			return "Directory used in a nondirectory operation";
307  		case ERR_FSAL_INVAL:
308  			return "Invalid object type";
309  		case ERR_FSAL_FBIG:
310  			return "File exceeds max file size";
311  		case ERR_FSAL_NOSPC:
312  			return "No space left on filesystem";
313  		case ERR_FSAL_ROFS:
314  			return "Read-only filesystem";
315  		case ERR_FSAL_MLINK:
316  			return "Too many hard links";
317  		case ERR_FSAL_DQUOT:
318  			return "Quota exceeded";
319  		case ERR_FSAL_NAMETOOLONG:
320  			return "Max name length exceeded";
321  		case ERR_FSAL_NOTEMPTY:
322  			return "The directory is not empty";
323  		case ERR_FSAL_STALE:
324  			return "The file no longer exists";
325  		case ERR_FSAL_BADHANDLE:
326  			return "Illegal filehandle";
327  		case ERR_FSAL_BADCOOKIE:
328  			return "Invalid cookie";
329  		case ERR_FSAL_NOTSUPP:
330  			return "Operation not supported";
331  		case ERR_FSAL_TOOSMALL:
332  			return "Output buffer too small";
333  		case ERR_FSAL_SERVERFAULT:
334  			return "Undefined server error";
335  		case ERR_FSAL_BADTYPE:
336  			return "Invalid type for create operation";
337  		case ERR_FSAL_DELAY:
338  			return "File busy, retry";
339  		case ERR_FSAL_FHEXPIRED:
340  			return "Filehandle expired";
341  		case ERR_FSAL_SYMLINK:
342  			return "This is a symbolic link, should be file/directory";
343  		case ERR_FSAL_ATTRNOTSUPP:
344  			return "Attribute not supported";
345  		case ERR_FSAL_NOT_INIT:
346  			return "Filesystem not initialized";
347  		case ERR_FSAL_ALREADY_INIT:
348  			return "Filesystem already initialised";
349  		case ERR_FSAL_BAD_INIT:
350  			return "Filesystem initialisation error";
351  		case ERR_FSAL_SEC:
352  			return "Security context error";
353  		case ERR_FSAL_NO_QUOTA:
354  			return "No Quota available";
355  		case ERR_FSAL_NOT_OPENED:
356  			return "File/directory not opened";
357  		case ERR_FSAL_DEADLOCK:
358  			return "Deadlock";
359  		case ERR_FSAL_OVERFLOW:
360  			return "Overflow";
361  		case ERR_FSAL_INTERRUPT:
362  			return "Operation Interrupted";
363  		case ERR_FSAL_BLOCKED:
364  			return "Lock Blocked";
365  		case ERR_FSAL_SHARE_DENIED:
366  			return "Share Denied";
367  		case ERR_FSAL_LOCKED:
368  			return "Locked";
369  		case ERR_FSAL_TIMEOUT:
370  			return "Timeout";
371  		case ERR_FSAL_FILE_OPEN:
372  			return "File Open";
373  		case ERR_FSAL_UNION_NOTSUPP:
374  			return "Union Not Supported";
375  		case ERR_FSAL_IN_GRACE:
376  			return "Server in Grace";
377  		case ERR_FSAL_NO_DATA:
378  			return "No Data";
379  		case ERR_FSAL_NO_ACE:
380  			return "No matching ACE";
381  		case ERR_FSAL_BAD_RANGE:
382  			return "Lock not in allowable range";
383  		case ERR_FSAL_CROSS_JUNCTION:
384  			return "Crossed Junction";
385  		case ERR_FSAL_BADNAME:
386  			return "Invalid Name";
387  		}
388  	
389  		return "Unknown FSAL error";
390  	}
391  	
392  	const char *fsal_dir_result_str(enum fsal_dir_result result)
393  	{
394  		switch (result) {
395  		case DIR_CONTINUE:
396  			return "DIR_CONTINUE";
397  	
398  		case DIR_READAHEAD:
399  			return "DIR_READAHEAD";
400  	
401  		case DIR_TERMINATE:
402  			return "DIR_TERMINATE";
403  		}
404  	
405  		return "<unknown>";
406  	}
407  	
408  	/**
409  	 * @brief Dump and fsal_staticfsinfo_t to a log
410  	 *
411  	 * This is used for debugging
412  	 *
413  	 * @param[in] info The info to dump
414  	 */
415  	void display_fsinfo(struct fsal_module *fsal)
416  	{
417  		LogDebug(COMPONENT_FSAL, "FileSystem info for FSAL %s {", fsal->name);
418  		LogDebug(COMPONENT_FSAL, "  maxfilesize  = %" PRIX64 "    ",
419  			 (uint64_t) fsal->fs_info.maxfilesize);
420  		LogDebug(COMPONENT_FSAL, "  maxlink  = %" PRIu32,
421  			fsal->fs_info.maxlink);
422  		LogDebug(COMPONENT_FSAL, "  maxnamelen  = %" PRIu32,
423  			fsal->fs_info.maxnamelen);
424  		LogDebug(COMPONENT_FSAL, "  maxpathlen  = %" PRIu32,
425  			fsal->fs_info.maxpathlen);
426  		LogDebug(COMPONENT_FSAL, "  no_trunc  = %d ",
427  			fsal->fs_info.no_trunc);
428  		LogDebug(COMPONENT_FSAL, "  chown_restricted  = %d ",
429  			 fsal->fs_info.chown_restricted);
430  		LogDebug(COMPONENT_FSAL, "  case_insensitive  = %d ",
431  			 fsal->fs_info.case_insensitive);
432  		LogDebug(COMPONENT_FSAL, "  case_preserving  = %d ",
433  			 fsal->fs_info.case_preserving);
434  		LogDebug(COMPONENT_FSAL, "  link_support  = %d  ",
435  			fsal->fs_info.link_support);
436  		LogDebug(COMPONENT_FSAL, "  symlink_support  = %d  ",
437  			 fsal->fs_info.symlink_support);
438  		LogDebug(COMPONENT_FSAL, "  lock_support  = %d  ",
439  			fsal->fs_info.lock_support);
440  		LogDebug(COMPONENT_FSAL, "  lock_support_async_block  = %d  ",
441  			 fsal->fs_info.lock_support_async_block);
442  		LogDebug(COMPONENT_FSAL, "  named_attr  = %d  ",
443  			fsal->fs_info.named_attr);
444  		LogDebug(COMPONENT_FSAL, "  unique_handles  = %d  ",
445  			 fsal->fs_info.unique_handles);
446  		LogDebug(COMPONENT_FSAL, "  acl_support  = %hu  ",
447  			fsal->fs_info.acl_support);
448  		LogDebug(COMPONENT_FSAL, "  cansettime  = %d  ",
449  			fsal->fs_info.cansettime);
450  		LogDebug(COMPONENT_FSAL, "  homogenous  = %d  ",
451  			fsal->fs_info.homogenous);
452  		LogDebug(COMPONENT_FSAL, "  supported_attrs  = %" PRIX64,
453  			 fsal->fs_info.supported_attrs);
454  		LogDebug(COMPONENT_FSAL, "  maxread  = %" PRIu64,
455  			fsal->fs_info.maxread);
456  		LogDebug(COMPONENT_FSAL, "  maxwrite  = %" PRIu64,
457  			fsal->fs_info.maxwrite);
458  		LogDebug(COMPONENT_FSAL, "  umask  = %X ",
459  			fsal->fs_info.umask);
460  		LogDebug(COMPONENT_FSAL, "  auth_exportpath_xdev  = %d  ",
461  			 fsal->fs_info.auth_exportpath_xdev);
462  		LogDebug(COMPONENT_FSAL, "  delegations = %d  ",
463  			 fsal->fs_info.delegations);
464  		LogDebug(COMPONENT_FSAL, "  pnfs_mds = %d  ",
465  			 fsal->fs_info.pnfs_mds);
466  		LogDebug(COMPONENT_FSAL, "  pnfs_ds = %d  ",
467  			 fsal->fs_info.pnfs_ds);
468  		LogDebug(COMPONENT_FSAL, "  fsal_trace = %d  ",
469  			 fsal->fs_info.fsal_trace);
470  		LogDebug(COMPONENT_FSAL, "  fsal_grace = %d  ",
471  			 fsal->fs_info.fsal_grace);
472  		LogDebug(COMPONENT_FSAL, "  expire_time_parent = %d  ",
473  			 fsal->fs_info.expire_time_parent);
474  		LogDebug(COMPONENT_FSAL, "}");
475  	}
476  	
477  	int display_attrlist(struct display_buffer *dspbuf,
478  			     struct attrlist *attr, bool is_obj)
479  	{
480  		int b_left = display_start(dspbuf);
481  	
482  		if (attr->request_mask == 0 && attr->valid_mask == 0 &&
483  		    attr->supported == 0)
484  			return display_cat(dspbuf, "No attributes");
485  	
486  		if (b_left > 0 && attr->request_mask != 0)
487  			b_left = display_printf(dspbuf, "Request Mask=%08x ",
488  						(unsigned int) attr->request_mask);
489  	
490  		if (b_left > 0 && attr->valid_mask != 0)
491  			b_left = display_printf(dspbuf, "Valid Mask=%08x ",
492  						(unsigned int) attr->valid_mask);
493  	
494  		if (b_left > 0 && attr->supported != 0)
495  			b_left = display_printf(dspbuf, "Supported Mask=%08x ",
496  						(unsigned int) attr->supported);
497  	
498  		if (b_left > 0 && is_obj)
499  			b_left = display_printf(dspbuf, "%s",
500  						object_file_type_to_str(attr->type));
501  	
502  		if (b_left > 0 && FSAL_TEST_MASK(attr->valid_mask, ATTR_NUMLINKS))
503  			b_left = display_printf(dspbuf, " numlinks=0x%"PRIx32,
504  						attr->numlinks);
505  	
506  		if (b_left > 0 && FSAL_TEST_MASK(attr->valid_mask, ATTR_SIZE))
507  			b_left = display_printf(dspbuf, " size=0x%"PRIx64,
508  						attr->filesize);
509  	
510  		if (b_left > 0 && FSAL_TEST_MASK(attr->valid_mask, ATTR_MODE))
511  			b_left = display_printf(dspbuf, " mode=0%"PRIo32,
512  						attr->mode);
513  	
514  		if (b_left > 0 && FSAL_TEST_MASK(attr->valid_mask, ATTR_OWNER))
515  			b_left = display_printf(dspbuf, " owner=0x%"PRIx64,
516  						attr->owner);
517  	
518  		if (b_left > 0 && FSAL_TEST_MASK(attr->valid_mask, ATTR_GROUP))
519  			b_left = display_printf(dspbuf, " group=0x%"PRIx64,
520  						attr->group);
521  	
522  		if (b_left > 0 && FSAL_TEST_MASK(attr->valid_mask, ATTR_ATIME_SERVER))
523  			b_left = display_cat(dspbuf, " atime=SERVER");
524  	
525  		if (b_left > 0 && FSAL_TEST_MASK(attr->valid_mask, ATTR_MTIME_SERVER))
526  			b_left = display_cat(dspbuf, " mtime=SERVER");
527  	
528  		if (b_left > 0 && FSAL_TEST_MASK(attr->valid_mask, ATTR_ATIME)) {
529  			b_left = display_cat(dspbuf, " atime=");
530  			if (b_left > 0)
531  				b_left = display_timespec(dspbuf, &attr->atime);
532  		}
533  	
534  		if (b_left > 0 && FSAL_TEST_MASK(attr->valid_mask, ATTR_MTIME)) {
535  			b_left = display_cat(dspbuf, " mtime=");
536  			if (b_left > 0)
537  				b_left = display_timespec(dspbuf, &attr->mtime);
538  		}
539  	
540  		return b_left;
541  	}
542  	
543  	void log_attrlist(log_components_t component, log_levels_t level,
544  			  const char *reason, struct attrlist *attr, bool is_obj,
545  			  char *file, int line, char *function)
546  	{
547  		char str[LOG_BUFF_LEN] = "\0";
548  		struct display_buffer dspbuf = {sizeof(str), str, str};
549  	
550  		(void) display_attrlist(&dspbuf, attr, is_obj);
551  	
552  		DisplayLogComponentLevel(component, file, line, function, level,
553  			"%s %s attributes %s",
554  			reason,
555  			is_obj ? "obj" : "set",
556  			str);
557  	}
558  	
559  	int open_dir_by_path_walk(int first_fd, const char *path, struct stat *stat)
560  	{
561  		char *name, *rest, *p;
562  		int fd = first_fd, len, rc, err;
563  	
564  		/* Get length of the path */
565  		len = strlen(path);
566  	
567  		/* Strip terminating '/' by shrinking length */
568  		while (path[len-1] == '/' && len > 1)
569  			len--;
570  	
571  		/* Allocate space for duplicate */
572  		name = alloca(len + 1);
573  	
574  		/* Copy the string */
575  		memcpy(name, path, len);
576  		/* Terminate it */
577  	
578  		name[len] = '\0';
579  	
580  		/* Determine if this is a relative path off some directory
581  		 * or an absolute path. If absolute path, open root dir.
582  		 */
583  		if (first_fd == -1) {
584  			if (name[0] != '/') {
585  				LogInfo(COMPONENT_FSAL,
586  					"Absolute path %s must start with '/'",
587  					path);
588  				return -EINVAL;
589  			}
590  			rest = name + 1;
591  			fd = open("/", O_RDONLY | O_NOFOLLOW);
592  		} else {
593  			rest = name;
594  			fd = dup(first_fd);
595  		}
596  	
597  		if (fd == -1) {
598  			err = errno;
599  			LogCrit(COMPONENT_FSAL,
600  				"Failed initial directory open for path %s with %s",
601  				path, strerror(err));
602  			return -err;
603  		}
604  	
605  		while (rest[0] != '\0') {
606  			/* Find the end of this path element */
607  			p = index(rest, '/');
608  	
609  			/* NUL terminate element (if not at end of string */
610  			if (p != NULL)
611  				*p = '\0';
612  	
613  			/* Skip extra '/' */
614  			if (rest[0] == '\0') {
615  				rest++;
616  				continue;
617  			}
618  	
619  			/* Disallow .. elements... */
620  			if (strcmp(rest, "..") == 0) {
621  				close(fd);
622  				LogInfo(COMPONENT_FSAL,
623  					"Failed due to '..' element in path %s",
624  					path);
625  				return -EACCES;
626  			}
627  	
628  			/* Open the next directory in the path */
629  			rc = openat(fd, rest, O_RDONLY | O_NOFOLLOW);
630  			err = errno;
631  	
632  			close(fd);
633  	
634  			if (rc == -1) {
635  				LogDebug(COMPONENT_FSAL,
636  					 "openat(%s) in path %s failed with %s",
637  					 rest, path, strerror(err));
638  				return -err;
639  			}
640  	
641  			fd = rc;
642  	
643  			/* Done, break out */
644  			if (p == NULL)
645  				break;
646  	
647  			/* Skip the '/' */
648  			rest = p+1;
649  		}
650  	
651  		rc = fstat(fd, stat);
652  		err = errno;
653  	
654  		if (rc == -1) {
655  			close(fd);
656  			LogDebug(COMPONENT_FSAL,
657  				 "fstat %s failed with %s",
658  				 path, strerror(err));
659  			return -err;
660  		}
661  	
662  		if (!S_ISDIR(stat->st_mode)) {
663  			close(fd);
664  			LogInfo(COMPONENT_FSAL,
665  				"Path %s is not a directory",
666  				path);
667  			return -ENOTDIR;
668  		}
669  	
670  		return fd;
671  	}
672  	
673  	pthread_rwlock_t fs_lock = PTHREAD_RWLOCK_INITIALIZER;
674  	
675  	struct glist_head posix_file_systems = {
676  		&posix_file_systems, &posix_file_systems
677  	};
678  	
679  	struct avltree avl_fsid;
680  	struct avltree avl_dev;
681  	
682  	static inline int
683  	fsal_fs_cmpf_fsid(const struct avltree_node *lhs,
684  			  const struct avltree_node *rhs)
685  	{
686  		struct fsal_filesystem *lk, *rk;
687  	
688  		lk = avltree_container_of(lhs, struct fsal_filesystem, avl_fsid);
689  		rk = avltree_container_of(rhs, struct fsal_filesystem, avl_fsid);
690  	
691  		if (lk->fsid_type < rk->fsid_type)
692  			return -1;
693  	
694  		if (lk->fsid_type > rk->fsid_type)
695  			return 1;
696  	
697  		if (lk->fsid.major < rk->fsid.major)
698  			return -1;
699  	
700  		if (lk->fsid.major > rk->fsid.major)
701  			return 1;
702  	
703  		/* No need to compare minors as they should be
704  		 * zeros if the type is FSID_MAJOR_64
705  		 */
706  		if (lk->fsid_type == FSID_MAJOR_64) {
707  			assert(rk->fsid_type == FSID_MAJOR_64);
708  			return 0;
709  		}
710  	
711  		if (lk->fsid.minor < rk->fsid.minor)
712  			return -1;
713  	
714  		if (lk->fsid.minor > rk->fsid.minor)
715  			return 1;
716  	
717  		return 0;
718  	}
719  	
720  	static inline struct fsal_filesystem *
721  	avltree_inline_fsid_lookup(const struct avltree_node *key)
722  	{
723  		struct avltree_node *node = avltree_inline_lookup(key, &avl_fsid,
724  								  fsal_fs_cmpf_fsid);
725  	
726  		if (node != NULL)
727  			return avltree_container_of(node, struct fsal_filesystem,
728  						    avl_fsid);
729  		else
730  			return NULL;
731  	}
732  	
733  	static inline int
734  	fsal_fs_cmpf_dev(const struct avltree_node *lhs,
735  			 const struct avltree_node *rhs)
736  	{
737  		struct fsal_filesystem *lk, *rk;
738  	
739  		lk = avltree_container_of(lhs, struct fsal_filesystem, avl_dev);
740  		rk = avltree_container_of(rhs, struct fsal_filesystem, avl_dev);
741  	
742  		if (lk->dev.major < rk->dev.major)
743  			return -1;
744  	
745  		if (lk->dev.major > rk->dev.major)
746  			return 1;
747  	
748  		if (lk->dev.minor < rk->dev.minor)
749  			return -1;
750  	
751  		if (lk->dev.minor > rk->dev.minor)
752  			return 1;
753  	
754  		return 0;
755  	}
756  	
757  	static inline struct fsal_filesystem *
758  	avltree_inline_dev_lookup(const struct avltree_node *key)
759  	{
760  		struct avltree_node *node = avltree_inline_lookup(key, &avl_dev,
761  								  fsal_fs_cmpf_dev);
762  	
763  		if (node != NULL)
764  			return avltree_container_of(node, struct fsal_filesystem,
765  						    avl_dev);
766  		else
767  			return NULL;
768  	}
769  	
770  	void remove_fs(struct fsal_filesystem *fs)
771  	{
772  		if (fs->in_fsid_avl)
773  			avltree_remove(&fs->avl_fsid, &avl_fsid);
774  	
775  		if (fs->in_dev_avl)
776  			avltree_remove(&fs->avl_dev, &avl_dev);
777  	
778  		glist_del(&fs->siblings);
779  		glist_del(&fs->filesystems);
780  	}
781  	
782  	void free_fs(struct fsal_filesystem *fs)
783  	{
784  		gsh_free(fs->path);
785  		gsh_free(fs->device);
786  		gsh_free(fs->type);
787  		gsh_free(fs);
788  	}
789  	
790  	int re_index_fs_fsid(struct fsal_filesystem *fs,
791  			     enum fsid_type fsid_type,
792  			     struct fsal_fsid__ *fsid)
793  	{
794  		struct avltree_node *node;
795  		struct fsal_fsid__ old_fsid = fs->fsid;
796  		enum fsid_type old_fsid_type = fs->fsid_type;
797  	
798  		LogDebug(COMPONENT_FSAL,
799  			 "Reindex %s from 0x%016"PRIx64".0x%016"PRIx64
800  			 " to 0x%016"PRIx64".0x%016"PRIx64,
801  			 fs->path,
802  			 fs->fsid.major, fs->fsid.minor,
803  			 fsid->major, fsid->minor);
804  	
805  		/* It is not valid to use this routine to
806  		 * remove fs from index.
807  		 */
808  		if (fsid_type == FSID_NO_TYPE)
809  			return -EINVAL;
810  	
811  		if (fs->in_fsid_avl)
812  			avltree_remove(&fs->avl_fsid, &avl_fsid);
813  	
814  		fs->fsid.major = fsid->major;
815  		fs->fsid.minor = fsid->minor;
816  		fs->fsid_type = fsid_type;
817  	
818  		node = avltree_insert(&fs->avl_fsid, &avl_fsid);
819  	
820  		if (node != NULL) {
821  			/* This is a duplicate file system. */
822  			fs->fsid = old_fsid;
823  			fs->fsid_type = old_fsid_type;
824  			if (fs->in_fsid_avl) {
825  				/* Put it back where it was */
826  				node = avltree_insert(&fs->avl_fsid, &avl_fsid);
827  				if (node != NULL) {
828  					LogFatal(COMPONENT_FSAL,
829  						 "Could not re-insert filesystem %s",
830  						 fs->path);
831  				}
832  			}
833  			return -EEXIST;
834  		}
835  	
836  		fs->in_fsid_avl = true;
837  	
838  		return 0;
839  	}
840  	
841  	int re_index_fs_dev(struct fsal_filesystem *fs,
842  			    struct fsal_dev__ *dev)
843  	{
844  		struct avltree_node *node;
845  		struct fsal_dev__ old_dev = fs->dev;
846  	
847  		/* It is not valid to use this routine to
848  		 * remove fs from index.
849  		 */
850  		if (dev == NULL)
851  			return -EINVAL;
852  	
853  		if (fs->in_dev_avl)
854  			avltree_remove(&fs->avl_dev, &avl_dev);
855  	
856  		fs->dev = *dev;
857  	
858  		node = avltree_insert(&fs->avl_dev, &avl_dev);
859  	
860  		if (node != NULL) {
861  			/* This is a duplicate file system. */
862  			fs->dev = old_dev;
863  			if (fs->in_dev_avl) {
864  				/* Put it back where it was */
865  				node = avltree_insert(&fs->avl_dev, &avl_dev);
866  				if (node != NULL) {
867  					LogFatal(COMPONENT_FSAL,
868  						 "Could not re-insert filesystem %s",
869  						 fs->path);
870  				}
871  			}
872  			return -EEXIST;
873  		}
874  	
875  		fs->in_dev_avl = true;
876  	
877  		return 0;
878  	}
879  	
880  	#define MASK_32 ((uint64_t) UINT32_MAX)
881  	
882  	int change_fsid_type(struct fsal_filesystem *fs,
883  			     enum fsid_type fsid_type)
884  	{
885  		struct fsal_fsid__ fsid = {0};
886  		bool valid = false;
887  	
888  		if (fs->fsid_type == fsid_type)
889  			return 0;
890  	
891  		switch (fsid_type) {
892  		case FSID_ONE_UINT64:
893  			if (fs->fsid_type == FSID_TWO_UINT64) {
894  				/* Use the same compression we use for NFS v3 fsid */
895  				fsid.major = squash_fsid(&fs->fsid);
896  				valid = true;
897  			} else if (fs->fsid_type == FSID_TWO_UINT32) {
898  				/* Put major in the high order 32 bits and minor
899  				 * in the low order 32 bits.
900  				 */
901  				fsid.major = fs->fsid.major << 32 |
902  					     fs->fsid.minor;
903  				valid = true;
904  			}
905  			fsid.minor = 0;
906  			break;
907  	
908  		case FSID_MAJOR_64:
909  			/* Nothing to do, will ignore fsid.minor in index */
910  			valid = true;
911  			fsid.major = fs->fsid.major;
912  			fsid.minor = fs->fsid.minor;
913  			break;
914  	
915  		case FSID_TWO_UINT64:
916  			if (fs->fsid_type == FSID_MAJOR_64) {
917  				/* Must re-index since minor was not indexed
918  				 * previously.
919  				 */
920  				fsid.major = fs->fsid.major;
921  				fsid.minor = fs->fsid.minor;
922  				valid = true;
923  			} else {
924  				/* Nothing to do, FSID_TWO_UINT32 will just have high
925  				 * order zero bits while FSID_ONE_UINT64 will have
926  				 * minor = 0, without changing the actual value.
927  				 */
928  				fs->fsid_type = fsid_type;
929  				return 0;
930  			}
931  			break;
932  	
933  		case FSID_DEVICE:
934  			fsid.major = fs->dev.major;
935  			fsid.minor = fs->dev.minor;
936  			valid = true;
937  	
938  		case FSID_TWO_UINT32:
939  			if (fs->fsid_type == FSID_TWO_UINT64) {
940  				/* Shrink each 64 bit quantity to 32 bits by xoring the
941  				 * two halves.
942  				 */
943  				fsid.major = (fs->fsid.major & MASK_32) ^
944  					     (fs->fsid.major >> 32);
945  				fsid.minor = (fs->fsid.minor & MASK_32) ^
946  					     (fs->fsid.minor >> 32);
947  				valid = true;
948  			} else if (fs->fsid_type == FSID_ONE_UINT64) {
949  				/* Split 64 bit that is in major into two 32 bit using
950  				 * the high order 32 bits as major.
951  				 */
952  				fsid.major = fs->fsid.major >> 32;
953  				fsid.minor = fs->fsid.major & MASK_32;
954  				valid = true;
955  			}
956  	
957  			break;
958  	
959  		case FSID_NO_TYPE:
960  			/* It is not valid to use this routine to remove an fs */
961  			break;
962  		}
963  	
964  		if (!valid)
965  			return -EINVAL;
966  	
967  		return re_index_fs_fsid(fs, fsid_type, &fsid);
968  	}
969  	
970  	static bool posix_get_fsid(struct fsal_filesystem *fs)
971  	{
972  		struct statfs stat_fs;
973  		struct stat mnt_stat;
974  	#ifdef USE_BLKID
975  		char *dev_name;
976  		char *uuid_str;
977  	#endif
978  	
979  		LogFullDebug(COMPONENT_FSAL, "statfs of %s pathlen %d", fs->path,
980  			     fs->pathlen);
981  	
982  		if (statfs(fs->path, &stat_fs) != 0)
983  			LogCrit(COMPONENT_FSAL,
984  				"stat_fs of %s resulted in error %s(%d)",
985  				fs->path, strerror(errno), errno);
986  	
987  	#if __FreeBSD__
988  		fs->namelen = stat_fs.f_namemax;
989  	#else
990  		fs->namelen = stat_fs.f_namelen;
991  	#endif
992  	
993  		if (stat(fs->path, &mnt_stat) != 0) {
994  			LogEvent(COMPONENT_FSAL,
995  				"stat of %s resulted in error %s(%d)",
996  				fs->path, strerror(errno), errno);
997  			return false;
998  		}
999  	
1000 		fs->dev = posix2fsal_devt(mnt_stat.st_dev);
1001 	
1002 		if (nfs_param.core_param.fsid_device) {
1003 			fs->fsid_type = FSID_DEVICE;
1004 			fs->fsid.major = fs->dev.major;
1005 			fs->fsid.minor = fs->dev.minor;
1006 			return true;
1007 		}
1008 	
1009 	#ifdef USE_BLKID
1010 		if (cache == NULL)
1011 			goto out;
1012 	
1013 		dev_name = blkid_devno_to_devname(mnt_stat.st_dev);
1014 	
1015 		if (dev_name == NULL) {
1016 			LogInfo(COMPONENT_FSAL,
1017 				"blkid_devno_to_devname of %s failed for dev %d.%d",
1018 				fs->path, major(mnt_stat.st_dev),
1019 				minor(mnt_stat.st_dev));
1020 			goto out;
1021 		}
1022 	
1023 		if (blkid_get_dev(cache, dev_name, BLKID_DEV_NORMAL) == NULL) {
1024 			LogInfo(COMPONENT_FSAL,
1025 				"blkid_get_dev of %s failed for devname %s",
1026 				fs->path, dev_name);
1027 			free(dev_name);
1028 			goto out;
1029 		}
1030 	
1031 		uuid_str = blkid_get_tag_value(cache, "UUID", dev_name);
1032 		free(dev_name);
1033 	
1034 		if  (uuid_str == NULL) {
1035 			LogInfo(COMPONENT_FSAL, "blkid_get_tag_value of %s failed",
1036 				fs->path);
1037 			goto out;
1038 		}
1039 	
1040 		if (uuid_parse(uuid_str, (char *) &fs->fsid) == -1) {
1041 			LogInfo(COMPONENT_FSAL, "uuid_parse of %s failed for uuid %s",
1042 				fs->path, uuid_str);
1043 			free(uuid_str);
1044 			goto out;
1045 		}
1046 	
1047 		free(uuid_str);
1048 		fs->fsid_type = FSID_TWO_UINT64;
1049 	
1050 		return true;
1051 	
1052 	out:
1053 	#endif
1054 		fs->fsid_type = FSID_TWO_UINT32;
1055 	#if __FreeBSD__
1056 		fs->fsid.major = (unsigned int) stat_fs.f_fsid.val[0];
1057 		fs->fsid.minor = (unsigned int) stat_fs.f_fsid.val[1];
1058 	#else
1059 		fs->fsid.major = (unsigned int) stat_fs.f_fsid.__val[0];
1060 		fs->fsid.minor = (unsigned int) stat_fs.f_fsid.__val[1];
1061 	#endif
1062 		if ((fs->fsid.major == 0) && (fs->fsid.minor == 0)) {
1063 			fs->fsid.major = fs->dev.major;
1064 			fs->fsid.minor = fs->dev.minor;
1065 		}
1066 	
1067 		return true;
1068 	}
1069 	
1070 	static void posix_create_file_system(struct mntent *mnt)
1071 	{
1072 		struct fsal_filesystem *fs;
1073 		struct avltree_node *node;
1074 	
1075 		if (strncasecmp(mnt->mnt_type, "nfs", 3) == 0) {
1076 			LogDebug(COMPONENT_FSAL,
1077 				 "Ignoring %s because type %s",
1078 				 mnt->mnt_dir,
1079 				 mnt->mnt_type);
1080 			return;
1081 		}
1082 	
1083 		fs = gsh_calloc(1, sizeof(*fs));
1084 	
1085 		fs->path = gsh_strdup(mnt->mnt_dir);
1086 		fs->device = gsh_strdup(mnt->mnt_fsname);
1087 		fs->type = gsh_strdup(mnt->mnt_type);
1088 	
1089 		if (!posix_get_fsid(fs)) {
1090 			free_fs(fs);
1091 			return;
1092 		}
1093 	
1094 		fs->pathlen = strlen(mnt->mnt_dir);
1095 	
1096 		node = avltree_insert(&fs->avl_fsid, &avl_fsid);
1097 	
1098 		if (node != NULL) {
1099 			/* This is a duplicate file system. */
1100 			struct fsal_filesystem *fs1;
1101 	
1102 			fs1 = avltree_container_of(node,
1103 						   struct fsal_filesystem,
1104 						   avl_fsid);
1105 	
1106 			LogDebug(COMPONENT_FSAL,
1107 				 "Skipped duplicate %s namelen=%d fsid=0x%016"PRIx64
1108 				 ".0x%016"PRIx64" %"PRIu64".%"PRIu64,
1109 				 fs->path, (int) fs->namelen,
1110 				 fs->fsid.major, fs->fsid.minor,
1111 				 fs->fsid.major, fs->fsid.minor);
1112 	
1113 			if (fs1->device[0] != '/' && fs->device[0] == '/') {
1114 				LogDebug(COMPONENT_FSAL,
1115 					 "Switching device for %s from %s to %s type from %s to %s",
1116 					 fs->path, fs1->device, fs->device,
1117 					 fs1->type, fs->type);
1118 				gsh_free(fs1->device);
1119 				fs1->device = fs->device;
1120 				fs->device = NULL;
1121 				gsh_free(fs1->type);
1122 				fs1->type = fs->type;
1123 				fs->type = NULL;
1124 			}
1125 	
1126 			free_fs(fs);
1127 			return;
1128 		}
1129 	
1130 		fs->in_fsid_avl = true;
1131 	
1132 		node = avltree_insert(&fs->avl_dev, &avl_dev);
1133 	
1134 		if (node != NULL) {
1135 			/* This is a duplicate file system. */
1136 			struct fsal_filesystem *fs1;
1137 	
1138 			fs1 = avltree_container_of(node,
1139 						   struct fsal_filesystem,
1140 						   avl_dev);
1141 	
1142 			LogDebug(COMPONENT_FSAL,
1143 				 "Skipped duplicate %s namelen=%d dev=%"
1144 				 PRIu64".%"PRIu64,
1145 				 fs->path, (int) fs->namelen,
1146 				 fs->dev.major, fs->dev.minor);
1147 	
1148 			if (fs1->device[0] != '/' && fs->device[0] == '/') {
1149 				LogDebug(COMPONENT_FSAL,
1150 					 "Switching device for %s from %s to %s type from %s to %s",
1151 					 fs->path, fs1->device, fs->device,
1152 					 fs1->type, fs->type);
1153 				gsh_free(fs1->device);
1154 				fs1->device = fs->device;
1155 				fs->device = NULL;
1156 				gsh_free(fs1->type);
1157 				fs1->type = fs->type;
1158 				fs->type = NULL;
1159 			}
1160 	
1161 			remove_fs(fs);
1162 			free_fs(fs);
1163 			return;
1164 		}
1165 	
1166 		fs->in_dev_avl = true;
1167 	
1168 		glist_add_tail(&posix_file_systems, &fs->filesystems);
1169 		glist_init(&fs->children);
1170 	
1171 		LogInfo(COMPONENT_FSAL,
1172 			"Added filesystem %s namelen=%d dev=%"PRIu64".%"PRIu64
1173 			" fsid=0x%016"PRIx64".0x%016"PRIx64" %"PRIu64".%"PRIu64,
1174 			fs->path, (int) fs->namelen,
1175 			fs->dev.major, fs->dev.minor,
1176 			fs->fsid.major, fs->fsid.minor,
1177 			fs->fsid.major, fs->fsid.minor);
1178 	}
1179 	
1180 	static void posix_find_parent(struct fsal_filesystem *this)
1181 	{
1182 		struct glist_head *glist;
1183 		struct fsal_filesystem *fs;
1184 		int plen = 0;
1185 	
1186 		/* Check if it already has parent */
1187 		if (this->parent != NULL)
1188 			return;
1189 	
1190 		/* Check for root fs, it has no parent */
1191 		if (this->pathlen == 1 && this->path[0] == '/')
1192 			return;
1193 	
1194 		glist_for_each(glist, &posix_file_systems) {
1195 			fs = glist_entry(glist, struct fsal_filesystem, filesystems);
1196 	
1197 			/* If this path is longer than this path, then it
1198 			 * can't be a parent, or if it's shorter than the
1199 			 * current match;
1200 			 */
1201 			if (fs->pathlen >= this->pathlen ||
1202 			    fs->pathlen < plen)
1203 				continue;
1204 	
1205 			/* Check for sub-string match */
1206 			if (strncmp(fs->path, this->path, fs->pathlen) != 0)
1207 				continue;
1208 	
1209 			/* Differentiate between /fs1 and /fs10 for parent of
1210 			 * /fs10/fs2, however, if fs->path is "/", we need to
1211 			 * special case.
1212 			 */
1213 			if (fs->pathlen != 1 &&
1214 			    this->path[fs->pathlen] != '/')
1215 				continue;
1216 	
1217 			this->parent = fs;
1218 			plen = fs->pathlen;
1219 		}
1220 	
1221 		if (this->parent == NULL) {
1222 			LogInfo(COMPONENT_FSAL,
1223 				"Unattached file system %s",
1224 				this->path);
1225 			return;
1226 		}
1227 	
1228 		/* Add to parent's list of children */
1229 		glist_add_tail(&this->parent->children, &this->siblings);
1230 		LogInfo(COMPONENT_FSAL,
1231 			"File system %s is a child of %s",
1232 			this->path, this->parent->path);
1233 	}
1234 	
1235 	void show_tree(struct fsal_filesystem *this, int nest)
1236 	{
1237 		struct glist_head *glist;
1238 		char blanks[1024];
1239 	
1240 		memset(blanks, ' ', nest * 2);
1241 		blanks[nest * 2] = '\0';
1242 	
1243 		LogInfo(COMPONENT_FSAL,
1244 			"%s%s",
1245 			blanks, this->path);
1246 	
1247 		/* Claim the children now */
1248 		glist_for_each(glist, &this->children) {
1249 			show_tree(glist_entry(glist,
1250 					      struct fsal_filesystem,
1251 					      siblings),
1252 				  nest + 1);
1253 		}
1254 	}
1255 	
1256 	int populate_posix_file_systems(bool force)
1257 	{
1258 		FILE *fp;
1259 		struct mntent *mnt;
1260 		struct stat st;
1261 		int retval = 0;
1262 		struct glist_head *glist;
1263 		struct fsal_filesystem *fs;
1264 	
1265 		PTHREAD_RWLOCK_wrlock(&fs_lock);
1266 	
1267 		if (glist_empty(&posix_file_systems)) {
1268 			LogDebug(COMPONENT_FSAL, "Initializing posix file systems");
1269 			avltree_init(&avl_fsid, fsal_fs_cmpf_fsid, 0);
1270 			avltree_init(&avl_dev, fsal_fs_cmpf_dev, 0);
1271 		} else if (!force) {
1272 			LogDebug(COMPONENT_FSAL, "File systems are initialized");
1273 			goto out;
1274 		}
1275 	
1276 		/* start looking for the mount point */
1277 		fp = setmntent(MOUNTED, "r");
1278 	
1279 		if (fp == NULL) {
1280 			retval = errno;
1281 			LogCrit(COMPONENT_FSAL, "Error %d in setmntent(%s): %s", retval,
1282 				MOUNTED, strerror(retval));
1283 			goto out;
1284 		}
1285 	
1286 	#ifdef USE_BLKID
1287 		if (blkid_get_cache(&cache, NULL) != 0)
1288 			LogInfo(COMPONENT_FSAL, "blkid_get_cache failed");
1289 	#endif
1290 	
1291 		while ((mnt = getmntent(fp)) != NULL) {
1292 			if (mnt->mnt_dir == NULL)
1293 				continue;
1294 	
1295 			if (stat(mnt->mnt_dir, &st) < 0 || !S_ISDIR(st.st_mode)) {
1296 				continue;
1297 			}
1298 	
1299 			posix_create_file_system(mnt);
1300 		}
1301 	
1302 	#ifdef USE_BLKID
1303 		if (cache) {
1304 			blkid_put_cache(cache);
1305 			cache = NULL;
1306 		}
1307 	#endif
1308 	
1309 		endmntent(fp);
1310 	
1311 		/* build tree of POSIX file systems */
1312 		glist_for_each(glist, &posix_file_systems)
1313 			posix_find_parent(glist_entry(glist, struct fsal_filesystem,
1314 						      filesystems));
1315 	
1316 		/* show tree */
1317 		glist_for_each(glist, &posix_file_systems) {
1318 			fs = glist_entry(glist, struct fsal_filesystem, filesystems);
1319 			if (fs->parent == NULL)
1320 				show_tree(fs, 0);
1321 		}
1322 	
1323 	 out:
1324 		PTHREAD_RWLOCK_unlock(&fs_lock);
1325 		return retval;
1326 	}
1327 	
1328 	int resolve_posix_filesystem(const char *path,
1329 				     struct fsal_module *fsal,
1330 				     struct fsal_export *exp,
1331 				     claim_filesystem_cb claim,
1332 				     unclaim_filesystem_cb unclaim,
1333 				     struct fsal_filesystem **root_fs)
1334 	{
1335 		int retval = 0;
1336 	
1337 		retval = populate_posix_file_systems(false);
1338 		if (retval != 0) {
1339 			LogCrit(COMPONENT_FSAL,
1340 				"populate_posix_file_systems returned %s (%d)",
1341 				strerror(retval), retval);
1342 			return retval;
1343 		}
1344 	
1345 		retval = claim_posix_filesystems(path, fsal, exp,
1346 						 claim, unclaim, root_fs);
1347 	
1348 		/* second attempt to resolve file system with force option in case of
1349 		 * ganesha isn't during startup.
1350 		 */
1351 		if (!nfs_init.init_complete || retval != EAGAIN)
1352 			return retval;
1353 	
1354 		LogDebug(COMPONENT_FSAL,
1355 			 "Call populate_posix_file_systems one more time");
1356 	
1357 		retval = populate_posix_file_systems(true);
1358 		if (retval != 0) {
1359 			LogCrit(COMPONENT_FSAL,
1360 				"populate_posix_file_systems returned %s (%d)",
1361 				strerror(retval), retval);
1362 			return retval;
1363 		}
1364 	
1365 		retval = claim_posix_filesystems(path, fsal, exp,
1366 						 claim, unclaim, root_fs);
1367 	
1368 		if (retval != 0) {
1369 			if (retval == EAGAIN)
1370 				retval = ENOENT;
1371 			LogCrit(COMPONENT_FSAL,
1372 				"claim_posix_filesystems(%s) returned %s (%d)",
1373 				path, strerror(retval), retval);
1374 		}
1375 	
1376 		return retval;
1377 	}
1378 	
1379 	void release_posix_file_system(struct fsal_filesystem *fs)
1380 	{
1381 		struct fsal_filesystem *child_fs;
1382 	
1383 		if (fs->unclaim != NULL) {
1384 			LogWarn(COMPONENT_FSAL,
1385 				"Filesystem %s is still claimed",
1386 				fs->path);
1387 			unclaim_fs(fs);
1388 		}
1389 	
1390 		while ((child_fs = glist_first_entry(&fs->children,
1391 						     struct fsal_filesystem,
1392 						     siblings))) {
1393 			release_posix_file_system(child_fs);
1394 		}
1395 	
1396 		LogDebug(COMPONENT_FSAL,
1397 			 "Releasing filesystem %s (%p)",
1398 			 fs->path, fs);
1399 		remove_fs(fs);
1400 		free_fs(fs);
1401 	}
1402 	
1403 	void release_posix_file_systems(void)
1404 	{
1405 		struct fsal_filesystem *fs;
1406 	
1407 		PTHREAD_RWLOCK_wrlock(&fs_lock);
1408 	
1409 		while ((fs = glist_first_entry(&posix_file_systems,
1410 					       struct fsal_filesystem, filesystems))) {
1411 			release_posix_file_system(fs);
1412 		}
1413 	
1414 		PTHREAD_RWLOCK_unlock(&fs_lock);
1415 	}
1416 	
1417 	struct fsal_filesystem *lookup_fsid_locked(struct fsal_fsid__ *fsid,
1418 						   enum fsid_type fsid_type)
1419 	{
1420 		struct fsal_filesystem key;
1421 	
1422 		key.fsid = *fsid;
1423 		key.fsid_type = fsid_type;
1424 		return avltree_inline_fsid_lookup(&key.avl_fsid);
1425 	}
1426 	
1427 	struct fsal_filesystem *lookup_dev_locked(struct fsal_dev__ *dev)
1428 	{
1429 		struct fsal_filesystem key;
1430 	
1431 		key.dev = *dev;
1432 		return avltree_inline_dev_lookup(&key.avl_dev);
1433 	}
1434 	
1435 	struct fsal_filesystem *lookup_fsid(struct fsal_fsid__ *fsid,
1436 					    enum fsid_type fsid_type)
1437 	{
1438 		struct fsal_filesystem *fs;
1439 	
1440 		PTHREAD_RWLOCK_rdlock(&fs_lock);
1441 	
1442 		fs = lookup_fsid_locked(fsid, fsid_type);
1443 	
1444 		PTHREAD_RWLOCK_unlock(&fs_lock);
1445 		return fs;
1446 	}
1447 	
1448 	struct fsal_filesystem *lookup_dev(struct fsal_dev__ *dev)
1449 	{
1450 		struct fsal_filesystem *fs;
1451 	
1452 		PTHREAD_RWLOCK_rdlock(&fs_lock);
1453 	
1454 		fs = lookup_dev_locked(dev);
1455 	
1456 		PTHREAD_RWLOCK_unlock(&fs_lock);
1457 	
1458 		return fs;
1459 	}
1460 	
1461 	void unclaim_fs(struct fsal_filesystem *this)
1462 	{
1463 		/* One call to unclaim resolves all claims to the filesystem */
1464 		if (this->unclaim != NULL) {
1465 			LogDebug(COMPONENT_FSAL,
1466 				 "Have FSAL %s unclaim filesystem %s",
1467 				 this->fsal->name, this->path);
1468 			this->unclaim(this);
1469 		}
1470 	
1471 		this->fsal = NULL;
1472 		this->unclaim = NULL;
1473 		this->exported = false;
1474 	}
1475 	
1476 	int process_claim(const char *path,
1477 			  int pathlen,
1478 			  struct fsal_filesystem *this,
1479 			  struct fsal_module *fsal,
1480 			  struct fsal_export *exp,
1481 			  claim_filesystem_cb claim,
1482 			  unclaim_filesystem_cb unclaim)
1483 	{
1484 		struct glist_head *glist;
1485 		struct fsal_filesystem *fs;
1486 		int retval = 0;
1487 	
1488 		/* Check if the filesystem is already directly exported by some other
1489 		 * FSAL - note we can only get here is this is the root filesystem for
1490 		 * the export, once we start processing nested filesystems, we skip
1491 		 * any that are directly exported.
1492 		 */
1493 		if (this->fsal != NULL && this->fsal != fsal && this->exported) {
1494 			LogCrit(COMPONENT_FSAL,
1495 				"Filesystem %s already exported by FSAL %s for export path %s",
1496 				this->path, this->fsal->name, path);
1497 			return EINVAL;
1498 		}
1499 	
1500 		/* Check if another FSAL had claimed this file system as a sub-mounted
1501 		 * file system.
1502 		 */
1503 		if (this->fsal != fsal)
1504 			unclaim_fs(this);
1505 	
1506 		/* Now claim the file system (we may call claim multiple times */
1507 		retval = claim(this, exp);
1508 	
1509 		if (retval == ENXIO) {
1510 			if (path != NULL) {
1511 				LogCrit(COMPONENT_FSAL,
1512 					"FSAL %s could not to claim root file system %s for export %s",
1513 					fsal->name, this->path, path);
1514 				return EINVAL;
1515 			} else {
1516 				LogInfo(COMPONENT_FSAL,
1517 					"FSAL %s could not to claim file system %s",
1518 					fsal->name, this->path);
1519 				return 0;
1520 			}
1521 		}
1522 	
1523 		if (retval != 0) {
1524 			LogCrit(COMPONENT_FSAL,
1525 				"FSAL %s failed to claim file system %s error %s",
1526 				fsal->name, this->path, strerror(retval));
1527 			return retval;
1528 		}
1529 	
1530 		LogDebug(COMPONENT_FSAL,
1531 			 "FSAL %s Claiming %s",
1532 			 fsal->name, this->path);
1533 	
1534 		/* Complete the claim */
1535 		this->fsal = fsal;
1536 		this->unclaim = unclaim;
1537 	
1538 		/* If this was the root of the export, indicate this filesystem is
1539 		 * directly exported.
1540 		 */
1541 		if (path != NULL)
1542 			this->exported = true;
1543 	
1544 		/* If this has no children, done */
1545 		if (glist_empty(&this->children))
1546 			return 0;
1547 	
1548 		/* Claim the children now */
1549 		glist_for_each(glist, &this->children) {
1550 			fs = glist_entry(glist, struct fsal_filesystem, siblings);
1551 			/* If path is provided, only consider children that are
1552 			 * children of the provided directory. This handles the
1553 			 * case of an export of something other than the root
1554 			 * of a file system.
1555 			 */
1556 			if (path != NULL && (fs->pathlen < pathlen ||
1557 			    (strncmp(fs->path, path, pathlen) != 0)))
1558 				continue;
1559 	
1560 			/* Test if this fs is directly exported, if so, no more
1561 			 * sub-mounted exports.
1562 			 */
1563 			if (fs->exported)
1564 				continue;
1565 	
1566 			/* Try to claim this child */
1567 			retval = process_claim(NULL, 0, fs, fsal,
1568 					       exp, claim, unclaim);
1569 	
1570 			if (retval != 0)
1571 				break;
1572 		}
1573 	
1574 		return retval;
1575 	}
1576 	
1577 	int claim_posix_filesystems(const char *path,
1578 				    struct fsal_module *fsal,
1579 				    struct fsal_export *exp,
1580 				    claim_filesystem_cb claim,
1581 				    unclaim_filesystem_cb unclaim,
1582 				    struct fsal_filesystem **root_fs)
1583 	{
1584 		int retval = 0;
1585 		struct fsal_filesystem *fs, *root = NULL;
1586 		struct glist_head *glist;
1587 		struct stat statbuf;
1588 		struct fsal_dev__ dev;
1589 	
1590 		PTHREAD_RWLOCK_wrlock(&fs_lock);
1591 	
1592 		if (stat(path, &statbuf) != 0) {
1593 			retval = errno;
1594 			LogCrit(COMPONENT_FSAL,
1595 				"Could not stat directory for path %s", path);
1596 			goto out;
1597 		}
1598 		dev = posix2fsal_devt(statbuf.st_dev);
1599 	
1600 		/* Scan POSIX file systems to find export root fs */
1601 		glist_for_each(glist, &posix_file_systems) {
1602 			fs = glist_entry(glist, struct fsal_filesystem, filesystems);
1603 			if (fs->dev.major == dev.major && fs->dev.minor == dev.minor) {
1604 				root = fs;
1605 				break;
1606 			}
1607 		}
1608 	
1609 		/* Check if we found a filesystem */
1610 		if (root == NULL) {
1611 			retval = EAGAIN;
1612 			goto out;
1613 		}
1614 	
1615 		/* Claim this file system and it's children */
1616 		retval = process_claim(path, strlen(path), root, fsal,
1617 				       exp, claim, unclaim);
1618 	
1619 		if (retval == 0) {
1620 			LogInfo(COMPONENT_FSAL,
1621 				"Root fs for export %s is %s",
1622 				path, root->path);
1623 			*root_fs = root;
1624 		}
1625 	
1626 	out:
1627 	
1628 		PTHREAD_RWLOCK_unlock(&fs_lock);
1629 		return retval;
1630 	}
1631 	
1632 	#ifdef USE_DBUS
1633 	
1634 	 /**
1635 	 *@brief Dbus method for showing dev ids of mounted POSIX filesystems
1636 	 *
1637 	 *@param[in]  args
1638 	 *@param[out] reply
1639 	 **/
1640 	static bool posix_showfs(DBusMessageIter *args,
1641 				 DBusMessage *reply,
1642 				 DBusError *error)
1643 	{
1644 		struct fsal_filesystem *fs;
1645 		struct glist_head *glist;
1646 		DBusMessageIter iter, sub_iter, fs_iter;
1647 		struct timespec timestamp;
1648 		uint64_t val;
1649 		char *path;
1650 	
1651 		dbus_message_iter_init_append(reply, &iter);
1652 		now(&timestamp);
1653 		dbus_append_timestamp(&iter, &timestamp);
1654 	
1655 		dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
1656 						 "(stt)",
1657 						 &sub_iter);
1658 	
1659 		PTHREAD_RWLOCK_rdlock(&fs_lock);
1660 		/* Traverse POSIX file systems to display dev ids */
1661 		glist_for_each(glist, &posix_file_systems) {
1662 			fs = glist_entry(glist, struct fsal_filesystem, filesystems);
1663 	
1664 			dbus_message_iter_open_container(&sub_iter,
1665 				DBUS_TYPE_STRUCT, NULL, &fs_iter);
1666 	
1667 			path = (fs->path != NULL) ? fs->path : "";
1668 			dbus_message_iter_append_basic(&fs_iter,
1669 				DBUS_TYPE_STRING, &path);
1670 	
1671 			val = fs->dev.major;
1672 			dbus_message_iter_append_basic(&fs_iter, DBUS_TYPE_UINT64,
1673 				&val);
1674 	
1675 			val = fs->dev.minor;
1676 			dbus_message_iter_append_basic(&fs_iter, DBUS_TYPE_UINT64,
1677 				&val);
1678 	
1679 			dbus_message_iter_close_container(&sub_iter,
1680 				&fs_iter);
1681 		}
1682 		PTHREAD_RWLOCK_unlock(&fs_lock);
1683 		dbus_message_iter_close_container(&iter, &sub_iter);
1684 		return true;
1685 	}
1686 	
1687 	static struct gsh_dbus_method cachemgr_show_fs = {
1688 		.name = "showfs",
1689 		.method = posix_showfs,
1690 		.args = {TIMESTAMP_REPLY,
1691 			{
1692 			  .name = "fss",
1693 			  .type = "a(stt)",
1694 			  .direction = "out"},
1695 			END_ARG_LIST}
1696 	};
1697 	
1698 	static struct gsh_dbus_method *cachemgr_methods[] = {
1699 		&cachemgr_show_fs,
1700 		NULL
1701 	};
1702 	
1703 	static struct gsh_dbus_interface cachemgr_table = {
1704 		.name = "org.ganesha.nfsd.cachemgr",
1705 		.props = NULL,
1706 		.methods = cachemgr_methods,
1707 		.signals = NULL
1708 	};
1709 	
1710 	/* DBUS list of interfaces on /org/ganesha/nfsd/CacheMgr
1711 	 * Intended for showing different caches
1712 	 */
1713 	
1714 	static struct gsh_dbus_interface *cachemgr_interfaces[] = {
1715 		&cachemgr_table,
1716 		NULL
1717 	};
1718 	
1719 	void dbus_cache_init(void)
1720 	{
1721 		gsh_dbus_register_path("CacheMgr", cachemgr_interfaces);
1722 	}
1723 	
1724 	#endif                          /* USE_DBUS */
1725 	
1726 	int encode_fsid(char *buf,
1727 			int max,
1728 			struct fsal_fsid__ *fsid,
1729 			enum fsid_type fsid_type)
1730 	{
1731 		uint32_t u32;
1732 	
1733 		if (sizeof_fsid(fsid_type) > max)
1734 			return -1;
1735 	
1736 		/* Pack fsid into the bytes */
1737 		switch (fsid_type) {
1738 		case FSID_NO_TYPE:
1739 			break;
1740 	
1741 		case FSID_ONE_UINT64:
1742 		case FSID_MAJOR_64:
1743 			memcpy(buf,
1744 			       &fsid->major,
1745 			       sizeof(fsid->major));
1746 			break;
1747 	
1748 		case FSID_TWO_UINT64:
1749 			memcpy(buf,
1750 			       fsid,
1751 			       sizeof(*fsid));
1752 			break;
1753 	
1754 		case FSID_TWO_UINT32:
1755 		case FSID_DEVICE:
1756 			u32 = fsid->major;
1757 			memcpy(buf,
1758 			       &u32,
1759 			       sizeof(u32));
1760 			u32 = fsid->minor;
1761 			memcpy(buf + sizeof(u32),
1762 			       &u32,
1763 			       sizeof(u32));
1764 		}
1765 	
1766 		return sizeof_fsid(fsid_type);
1767 	}
1768 	
1769 	int decode_fsid(char *buf,
1770 			int max,
1771 			struct fsal_fsid__ *fsid,
1772 			enum fsid_type fsid_type)
1773 	{
1774 		uint32_t u32;
1775 	
1776 		if (sizeof_fsid(fsid_type) > max)
1777 			return -1;
1778 	
1779 		switch (fsid_type) {
1780 		case FSID_NO_TYPE:
1781 			memset(fsid, 0, sizeof(*fsid));
1782 			break;
1783 	
1784 		case FSID_ONE_UINT64:
1785 		case FSID_MAJOR_64:
1786 			memcpy(&fsid->major,
1787 			       buf,
1788 			       sizeof(fsid->major));
1789 			fsid->minor = 0;
1790 			break;
1791 	
1792 		case FSID_TWO_UINT64:
1793 			memcpy(fsid,
1794 			       buf,
1795 			       sizeof(*fsid));
1796 			break;
1797 	
1798 		case FSID_TWO_UINT32:
1799 		case FSID_DEVICE:
1800 			memcpy(&u32,
1801 			       buf,
1802 			       sizeof(u32));
1803 			fsid->major = u32;
1804 			memcpy(&u32,
1805 			       buf + sizeof(u32),
1806 			       sizeof(u32));
1807 			fsid->minor = u32;
1808 			break;
1809 		}
1810 	
1811 		return sizeof_fsid(fsid_type);
1812 	}
1813 	
1814 	
1815 	static inline bool is_dup_ace(fsal_ace_t *ace, fsal_aceflag_t inherit)
1816 	{
1817 		if (!IS_FSAL_ACE_INHERIT(*ace))
1818 			return false;
1819 		if (inherit != FSAL_ACE_FLAG_DIR_INHERIT)
1820 			/* Only dup on directories */
1821 			return false;
1822 		if (IS_FSAL_ACE_NO_PROPAGATE(*ace))
1823 			return false;
1824 		if (IS_FSAL_ACE_FILE_INHERIT(*ace) && !IS_FSAL_ACE_DIR_INHERIT(*ace))
1825 			return false;
1826 		if (!IS_FSAL_ACE_PERM(*ace))
1827 			return false;
1828 	
1829 		return true;
1830 	}
1831 	
1832 	static fsal_errors_t dup_ace(fsal_ace_t *sace, fsal_ace_t *dace)
1833 	{
1834 		*dace = *sace;
1835 	
1836 		GET_FSAL_ACE_FLAG(*sace) |= FSAL_ACE_FLAG_INHERIT_ONLY;
1837 	
1838 		GET_FSAL_ACE_FLAG(*dace) &= ~(FSAL_ACE_FLAG_INHERIT |
1839 					      FSAL_ACE_FLAG_NO_PROPAGATE);
1840 	
1841 		return ERR_FSAL_NO_ERROR;
1842 	}
1843 	
1844 	fsal_errors_t fsal_inherit_acls(struct attrlist *attrs, fsal_acl_t *sacl,
1845 					fsal_aceflag_t inherit)
1846 	{
1847 		int naces;
1848 		fsal_ace_t *sace, *dace;
1849 	
1850 		if (!sacl || !sacl->aces || sacl->naces == 0)
1851 			return ERR_FSAL_NO_ERROR;
1852 	
1853 		if (attrs->acl && attrs->acl->aces && attrs->acl->naces > 0)
1854 			return ERR_FSAL_EXIST;
1855 	
1856 		naces = 0;
1857 		for (sace = sacl->aces; sace < sacl->aces + sacl->naces; sace++) {
1858 			if (IS_FSAL_ACE_FLAG(*sace, inherit))
1859 				naces++;
1860 			if (is_dup_ace(sace, inherit))
1861 				naces++;
1862 		}
1863 	
1864 		if (naces == 0)
1865 			return ERR_FSAL_NO_ERROR;
1866 	
1867 		if (attrs->acl != NULL) {
1868 			/* We should never be passed attributes that have an
1869 			 * ACL attached, but just in case some future code
1870 			 * path changes that assumption, let's not release the
1871 			 * old ACL properly.
1872 			 */
1873 			int acl_status;
1874 	
1875 			acl_status = nfs4_acl_release_entry(attrs->acl);
1876 	
1877 			if (acl_status != NFS_V4_ACL_SUCCESS)
1878 				LogCrit(COMPONENT_FSAL,
1879 					"Failed to release old acl, status=%d",
1880 					acl_status);
1881 		}
1882 	
1883 		attrs->acl = nfs4_acl_alloc();
1884 		attrs->acl->aces = (fsal_ace_t *) nfs4_ace_alloc(naces);
1885 		dace = attrs->acl->aces;
1886 	
1887 		for (sace = sacl->aces; sace < sacl->aces + sacl->naces; sace++) {
1888 			if (IS_FSAL_ACE_FLAG(*sace, inherit)) {
1889 				*dace = *sace;
1890 				if (IS_FSAL_ACE_NO_PROPAGATE(*dace))
1891 					GET_FSAL_ACE_FLAG(*dace) &=
1892 						~(FSAL_ACE_FLAG_INHERIT |
1893 						  FSAL_ACE_FLAG_NO_PROPAGATE);
1894 				else if (inherit == FSAL_ACE_FLAG_DIR_INHERIT &&
1895 					 IS_FSAL_ACE_FILE_INHERIT(*dace) &&
1896 					 !IS_FSAL_ACE_DIR_INHERIT(*dace))
1897 					GET_FSAL_ACE_FLAG(*dace) |=
1898 						FSAL_ACE_FLAG_NO_PROPAGATE;
1899 				else if (is_dup_ace(dace, inherit)) {
1900 					dup_ace(dace, dace + 1);
1901 					dace++;
1902 				}
1903 				dace++;
1904 			}
1905 		}
1906 		attrs->acl->naces = naces;
1907 		FSAL_SET_MASK(attrs->valid_mask, ATTR_ACL);
1908 	
1909 		return ERR_FSAL_NO_ERROR;
1910 	}
1911 	
1912 	fsal_status_t fsal_remove_access(struct fsal_obj_handle *dir_hdl,
1913 					 struct fsal_obj_handle *rem_hdl,
1914 					 bool isdir)
1915 	{
1916 		fsal_status_t fsal_status = { 0, 0 };
1917 		fsal_status_t del_status = { 0, 0 };
1918 	
1919 		/* draft-ietf-nfsv4-acls section 12 */
1920 		/* If no execute on dir, deny */
1921 		fsal_status = dir_hdl->obj_ops->test_access(
1922 					dir_hdl,
1923 					FSAL_MODE_MASK_SET(FSAL_X_OK) |
1924 					FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_EXECUTE),
1925 					NULL, NULL, false);
1926 		if (FSAL_IS_ERROR(fsal_status)) {
1927 			LogFullDebug(COMPONENT_FSAL,
1928 				 "Could not delete: No execute permession on parent: %s",
1929 				 msg_fsal_err(fsal_status.major));
1930 			return fsal_status;
1931 		}
1932 	
1933 		/* We can delete if we have *either* ACE_PERM_DELETE or
1934 		 * ACE_PERM_DELETE_CHILD.  7530 - 6.2.1.3.2 */
1935 		del_status = rem_hdl->obj_ops->test_access(
1936 					rem_hdl,
1937 					FSAL_MODE_MASK_SET(FSAL_W_OK) |
1938 					FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_DELETE) |
1939 					FSAL_ACE4_REQ_FLAG,
1940 					NULL, NULL, false);
1941 		fsal_status = dir_hdl->obj_ops->test_access(
1942 					dir_hdl,
1943 					FSAL_MODE_MASK_SET(FSAL_W_OK) |
1944 					FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_DELETE_CHILD) |
1945 					FSAL_ACE4_REQ_FLAG,
1946 					NULL, NULL, false);
1947 		if (FSAL_IS_ERROR(fsal_status) && FSAL_IS_ERROR(del_status)) {
1948 			/* Neither was explicitly allowed */
1949 			if (fsal_status.major != ERR_FSAL_NO_ACE) {
1950 				/* Explicitly denied */
1951 				LogFullDebug(COMPONENT_FSAL,
1952 					 "Could not delete (DELETE_CHILD) %s",
1953 					 msg_fsal_err(fsal_status.major));
1954 				return fsal_status;
1955 			}
1956 			if (del_status.major != ERR_FSAL_NO_ACE) {
1957 				/* Explicitly denied */
1958 				LogFullDebug(COMPONENT_FSAL,
1959 					 "Could not delete (DELETE) %s",
1960 					 msg_fsal_err(del_status.major));
1961 				return del_status;
1962 			}
1963 	
1964 			/* Neither ACE_PERM_DELETE nor ACE_PERM_DELETE_CHILD are set.
1965 			 * Check for ADD_FILE in parent */
1966 			fsal_status = dir_hdl->obj_ops->test_access(
1967 					dir_hdl,
1968 					FSAL_MODE_MASK_SET(FSAL_W_OK) |
1969 					FSAL_ACE4_MASK_SET(isdir ?
1970 						   FSAL_ACE_PERM_ADD_SUBDIRECTORY
1971 						   : FSAL_ACE_PERM_ADD_FILE),
1972 					NULL, NULL, false);
1973 	
1974 			if (FSAL_IS_ERROR(fsal_status)) {
1975 				LogFullDebug(COMPONENT_FSAL,
1976 					 "Could not delete (ADD_CHILD) %s",
1977 					 msg_fsal_err(fsal_status.major));
1978 				return fsal_status;
1979 			}
1980 			/* Allowed; fall through */
1981 		}
1982 	
1983 		return fsalstat(ERR_FSAL_NO_ERROR, 0);
1984 	}
1985 	
1986 	fsal_status_t fsal_rename_access(struct fsal_obj_handle *src_dir_hdl,
1987 					 struct fsal_obj_handle *src_obj_hdl,
1988 					 struct fsal_obj_handle *dst_dir_hdl,
1989 					 struct fsal_obj_handle *dst_obj_hdl,
1990 					 bool isdir)
1991 	{
1992 		fsal_status_t status = {0, 0};
1993 		fsal_accessflags_t access_type;
1994 	
1995 		status = fsal_remove_access(src_dir_hdl, src_obj_hdl, isdir);
1996 		if (FSAL_IS_ERROR(status))
1997 			return status;
1998 	
1999 		if (dst_obj_hdl) {
2000 			status = fsal_remove_access(dst_dir_hdl, dst_obj_hdl, isdir);
2001 			if (FSAL_IS_ERROR(status))
2002 				return status;
2003 		}
2004 	
2005 		access_type = FSAL_MODE_MASK_SET(FSAL_W_OK);
2006 		if (isdir)
2007 			access_type |=
2008 				FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_SUBDIRECTORY);
2009 		else
2010 			access_type |= FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE);
2011 		status = dst_dir_hdl->obj_ops->test_access(dst_dir_hdl, access_type,
2012 							  NULL, NULL, false);
2013 		if (FSAL_IS_ERROR(status))
2014 			return status;
2015 	
2016 		return fsalstat(ERR_FSAL_NO_ERROR, 0);
2017 	}
2018 	
2019 	static fsal_status_t
2020 	fsal_mode_set_ace(fsal_ace_t *deny, fsal_ace_t *allow, uint32_t mode)
2021 	{
2022 		GET_FSAL_ACE_TYPE(*allow) = FSAL_ACE_TYPE_ALLOW;
2023 		GET_FSAL_ACE_TYPE(*deny) = FSAL_ACE_TYPE_DENY;
2024 	
2025 		if (mode & S_IRUSR)
2026 			GET_FSAL_ACE_PERM(*allow) |= FSAL_ACE_PERM_READ_DATA;
2027 		else
2028 			GET_FSAL_ACE_PERM(*deny) |= FSAL_ACE_PERM_READ_DATA;
2029 		if (mode & S_IWUSR)
2030 			GET_FSAL_ACE_PERM(*allow) |=
2031 				FSAL_ACE_PERM_WRITE_DATA | FSAL_ACE_PERM_APPEND_DATA;
2032 		else
2033 			GET_FSAL_ACE_PERM(*deny) |=
2034 				FSAL_ACE_PERM_WRITE_DATA | FSAL_ACE_PERM_APPEND_DATA;
2035 		if (mode & S_IXUSR)
2036 			GET_FSAL_ACE_PERM(*allow) |= FSAL_ACE_PERM_EXECUTE;
2037 		else
2038 			GET_FSAL_ACE_PERM(*deny) |= FSAL_ACE_PERM_EXECUTE;
2039 	
2040 		return fsalstat(ERR_FSAL_NO_ERROR, 0);
2041 	}
2042 	
2043 	static fsal_status_t
2044 	fsal_mode_gen_set(fsal_ace_t *ace, uint32_t mode)
2045 	{
2046 		fsal_ace_t *allow, *deny;
2047 	
2048 		/* @OWNER */
2049 		deny = ace;
2050 		allow = deny + 1;
2051 		GET_FSAL_ACE_USER(*allow) = FSAL_ACE_SPECIAL_OWNER;
2052 		GET_FSAL_ACE_IFLAG(*allow) |= (FSAL_ACE_IFLAG_MODE_GEN |
2053 					       FSAL_ACE_IFLAG_SPECIAL_ID);
2054 		GET_FSAL_ACE_USER(*deny) = FSAL_ACE_SPECIAL_OWNER;
2055 		GET_FSAL_ACE_IFLAG(*deny) |= (FSAL_ACE_IFLAG_MODE_GEN |
2056 					      FSAL_ACE_IFLAG_SPECIAL_ID);
2057 		fsal_mode_set_ace(deny, allow, mode & S_IRWXU);
2058 		/* @GROUP */
2059 		deny += 2;
2060 		allow = deny + 1;
2061 		GET_FSAL_ACE_USER(*allow) = FSAL_ACE_SPECIAL_GROUP;
2062 		GET_FSAL_ACE_IFLAG(*allow) |= (FSAL_ACE_IFLAG_MODE_GEN |
2063 					       FSAL_ACE_IFLAG_SPECIAL_ID);
2064 		GET_FSAL_ACE_FLAG(*allow) = FSAL_ACE_FLAG_GROUP_ID;
2065 		GET_FSAL_ACE_USER(*deny) = FSAL_ACE_SPECIAL_GROUP;
2066 		GET_FSAL_ACE_IFLAG(*deny) |= (FSAL_ACE_IFLAG_MODE_GEN |
2067 					      FSAL_ACE_IFLAG_SPECIAL_ID);
2068 		GET_FSAL_ACE_FLAG(*deny) = FSAL_ACE_FLAG_GROUP_ID;
2069 		fsal_mode_set_ace(deny, allow, (mode & S_IRWXG) << 3);
2070 		/* @EVERYONE */
2071 		deny += 2;
2072 		allow = deny + 1;
2073 		GET_FSAL_ACE_USER(*allow) = FSAL_ACE_SPECIAL_EVERYONE;
2074 		GET_FSAL_ACE_IFLAG(*allow) |= (FSAL_ACE_IFLAG_MODE_GEN |
2075 					       FSAL_ACE_IFLAG_SPECIAL_ID);
2076 		GET_FSAL_ACE_USER(*deny) = FSAL_ACE_SPECIAL_EVERYONE;
2077 		GET_FSAL_ACE_IFLAG(*deny) |= (FSAL_ACE_IFLAG_MODE_GEN |
2078 					      FSAL_ACE_IFLAG_SPECIAL_ID);
2079 		fsal_mode_set_ace(deny, allow, (mode & S_IRWXO) << 6);
2080 	
2081 		return fsalstat(ERR_FSAL_NO_ERROR, 0);
2082 	}
2083 	
2084 	static fsal_status_t
2085 	fsal_mode_gen_acl(struct attrlist *attrs)
2086 	{
2087 		if (attrs->acl != NULL) {
2088 			/* We should never be passed attributes that have an
2089 			 * ACL attached, but just in case some future code
2090 			 * path changes that assumption, let's not release the
2091 			 * old ACL properly.
2092 			 */
2093 			int acl_status;
2094 	
2095 			acl_status = nfs4_acl_release_entry(attrs->acl);
2096 	
2097 			if (acl_status != NFS_V4_ACL_SUCCESS)
2098 				LogCrit(COMPONENT_FSAL,
2099 					"Failed to release old acl, status=%d",
2100 					acl_status);
2101 		}
2102 	
2103 		attrs->acl = nfs4_acl_alloc();
2104 		attrs->acl->naces = 6;
2105 		attrs->acl->aces = (fsal_ace_t *) nfs4_ace_alloc(attrs->acl->naces);
2106 	
2107 		fsal_mode_gen_set(attrs->acl->aces, attrs->mode);
2108 	
2109 		FSAL_SET_MASK(attrs->valid_mask, ATTR_ACL);
2110 	
2111 		return fsalstat(ERR_FSAL_NO_ERROR, 0);
2112 	}
2113 	
2114 	fsal_status_t fsal_mode_to_acl(struct attrlist *attrs, fsal_acl_t *sacl)
2115 	{
2116 		int naces;
2117 		fsal_ace_t *sace, *dace;
2118 	
2119 		if (!FSAL_TEST_MASK(attrs->valid_mask, ATTR_MODE))
2120 			return fsalstat(ERR_FSAL_NO_ERROR, 0);
2121 	
2122 		if (!sacl || sacl->naces == 0)
2123 			return fsal_mode_gen_acl(attrs);
2124 	
2125 		naces = 0;
2126 		for (sace = sacl->aces; sace < sacl->aces + sacl->naces; sace++) {
2127 			if (IS_FSAL_ACE_MODE_GEN(*sace)) {
2128 				/* Don't copy mode geneated ACEs; will be re-created */
2129 				continue;
2130 			}
2131 	
2132 			naces++;
2133 			if (IS_FSAL_ACE_INHERIT_ONLY(*sace))
2134 				continue;
2135 			if (!IS_FSAL_ACE_PERM(*sace))
2136 				continue;
2137 			if (IS_FSAL_ACE_INHERIT(*sace)) {
2138 				/* Dup this ACE */
2139 				naces++;
2140 			}
2141 			/* XXX dang dup for non-special case */
2142 		}
2143 	
2144 		if (naces == 0) {
2145 			/* Only mode generate aces */
2146 			return fsal_mode_gen_acl(attrs);
2147 		}
2148 	
2149 		/* Space for generated ACEs at the end */
2150 		naces += 6;
2151 	
2152 		if (attrs->acl != NULL) {
2153 			/* We should never be passed attributes that have an
2154 			 * ACL attached, but just in case some future code
2155 			 * path changes that assumption, let's not release the
2156 			 * old ACL properly.
2157 			 */
2158 			int acl_status;
2159 	
2160 			acl_status = nfs4_acl_release_entry(attrs->acl);
2161 	
2162 			if (acl_status != NFS_V4_ACL_SUCCESS)
2163 				LogCrit(COMPONENT_FSAL,
2164 					"Failed to release old acl, status=%d",
2165 					acl_status);
2166 		}
2167 	
2168 		attrs->acl = nfs4_acl_alloc();
2169 		attrs->acl->aces = (fsal_ace_t *) nfs4_ace_alloc(naces);
2170 		attrs->acl->naces = 0;
2171 		dace = attrs->acl->aces;
2172 	
2173 		for (sace = sacl->aces; sace < sacl->aces + sacl->naces;
2174 		     sace++, dace++) {
2175 			if (IS_FSAL_ACE_MODE_GEN(*sace))
2176 				continue;
2177 	
2178 			*dace = *sace;
2179 			attrs->acl->naces++;
2180 	
2181 			if (IS_FSAL_ACE_INHERIT_ONLY(*dace) ||
2182 			    (!IS_FSAL_ACE_PERM(*dace)))
2183 				continue;
2184 	
2185 			if (IS_FSAL_ACE_INHERIT(*dace)) {
2186 				/* Need to duplicate */
2187 				GET_FSAL_ACE_FLAG(*dace) |= FSAL_ACE_FLAG_INHERIT_ONLY;
2188 				dace++;
2189 				*dace = *sace;
2190 				attrs->acl->naces++;
2191 				GET_FSAL_ACE_FLAG(*dace) &= ~(FSAL_ACE_FLAG_INHERIT);
2192 			}
2193 	
2194 			if (IS_FSAL_ACE_SPECIAL(*dace)) {
2195 				GET_FSAL_ACE_PERM(*dace) &=
2196 					~(FSAL_ACE_PERM_READ_DATA |
2197 					  FSAL_ACE_PERM_LIST_DIR |
2198 					  FSAL_ACE_PERM_WRITE_DATA |
2199 					  FSAL_ACE_PERM_ADD_FILE |
2200 					  FSAL_ACE_PERM_APPEND_DATA |
2201 					  FSAL_ACE_PERM_ADD_SUBDIRECTORY |
2202 					  FSAL_ACE_PERM_EXECUTE);
2203 			} else {
2204 				/* Do non-special stuff */
2205 			}
2206 		}
2207 	
2208 		if (naces - attrs->acl->naces != 6) {
2209 			LogDebug(COMPONENT_FSAL, "Bad naces: %d not %d",
2210 				 attrs->acl->naces, naces - 6);
2211 			return fsalstat(ERR_FSAL_SERVERFAULT, 0);
2212 		}
2213 	
2214 		fsal_mode_gen_set(dace, attrs->mode);
2215 	
2216 		attrs->acl->naces = naces;
2217 		FSAL_SET_MASK(attrs->valid_mask, ATTR_ACL);
2218 	
2219 		return fsalstat(ERR_FSAL_NO_ERROR, 0);
2220 	}
2221 	
2222 	/* fsal_acl_to_mode helpers
2223 	 */
2224 	
2225 	static uint32_t ace_modes[3][3] = {
2226 		{ /* owner */
2227 			S_IRUSR, S_IWUSR, S_IXUSR
2228 		},
2229 		{ /* group */
2230 			S_IRGRP, S_IWGRP, S_IXGRP
2231 		},
2232 		{ /* everyone */
2233 			S_IRUSR | S_IRGRP | S_IROTH,
2234 			S_IWUSR | S_IWGRP | S_IWOTH,
2235 			S_IXUSR | S_IXGRP | S_IXOTH,
2236 		}
2237 	};
2238 	
2239 	static inline void set_mode(struct attrlist *attrs, uint32_t mode, bool allow)
2240 	{
2241 		if (allow)
2242 			attrs->mode |= mode;
2243 		else
2244 			attrs->mode &= ~(mode);
2245 	}
2246 	
2247 	fsal_status_t fsal_acl_to_mode(struct attrlist *attrs)
2248 	{
2249 		fsal_ace_t *ace = NULL;
2250 		uint32_t *modes;
2251 	
2252 		if (!FSAL_TEST_MASK(attrs->valid_mask, ATTR_ACL))
2253 			return fsalstat(ERR_FSAL_NO_ERROR, 0);
2254 		if (!attrs->acl || attrs->acl->naces == 0)
2255 			return fsalstat(ERR_FSAL_NO_ERROR, 0);
2256 	
2257 		for (ace = attrs->acl->aces; ace < attrs->acl->aces + attrs->acl->naces;
2258 		     ace++) {
2259 			if (IS_FSAL_ACE_SPECIAL_OWNER(*ace))
2260 				modes = ace_modes[0];
2261 			else if (IS_FSAL_ACE_SPECIAL_GROUP(*ace))
2262 				modes = ace_modes[1];
2263 			else if (IS_FSAL_ACE_SPECIAL_EVERYONE(*ace))
2264 				modes = ace_modes[2];
2265 			else
2266 				continue;
2267 	
2268 			if (IS_FSAL_ACE_READ_DATA(*ace))
2269 				set_mode(attrs, modes[0], IS_FSAL_ACE_ALLOW(*ace));
2270 			if (IS_FSAL_ACE_WRITE_DATA(*ace) ||
2271 			    IS_FSAL_ACE_APPEND_DATA(*ace))
2272 				set_mode(attrs, modes[1], IS_FSAL_ACE_ALLOW(*ace));
2273 			if (IS_FSAL_ACE_EXECUTE(*ace))
2274 				set_mode(attrs, modes[2], IS_FSAL_ACE_ALLOW(*ace));
2275 	
2276 		}
2277 	
2278 		FSAL_SET_MASK(attrs->valid_mask, ATTR_MODE);
2279 		return fsalstat(ERR_FSAL_NO_ERROR, 0);
2280 	}
2281 	
2282 	void set_common_verifier(struct attrlist *attrs, fsal_verifier_t verifier)
2283 	{
2284 		uint32_t verf_hi = 0, verf_lo = 0;
2285 	
2286 		memcpy(&verf_hi,
2287 		       verifier,
2288 		       sizeof(uint32_t));
2289 		memcpy(&verf_lo,
2290 		       verifier + sizeof(uint32_t),
2291 		       sizeof(uint32_t));
2292 	
2293 		LogFullDebug(COMPONENT_FSAL,
2294 			     "Passed verifier %"PRIx32" %"PRIx32,
2295 			     verf_hi, verf_lo);
2296 	
2297 		if (isDebug(COMPONENT_FSAL) &&
2298 		    (FSAL_TEST_MASK(attrs->valid_mask, ATTR_ATIME) ||
2299 		    (FSAL_TEST_MASK(attrs->valid_mask, ATTR_MTIME)))) {
2300 			LogWarn(COMPONENT_FSAL,
2301 				"atime or mtime was already set in attributes%"
2302 				PRIx32" %"PRIx32,
2303 				(uint32_t) attrs->atime.tv_sec,
2304 				(uint32_t) attrs->mtime.tv_sec);
2305 		}
2306 	
2307 		attrs->atime.tv_sec = verf_hi;
2308 		attrs->mtime.tv_sec = verf_lo;
2309 	
2310 		FSAL_SET_MASK(attrs->valid_mask, ATTR_ATIME | ATTR_MTIME);
2311 	}
2312 	
2313 	/**
2314 	 * @brief Update the ref counter of share state
2315 	 *
2316 	 * The caller is responsible for protecting the share.
2317 	 *
2318 	 * @param[in] share         Share to update
2319 	 * @param[in] old_openflags Previous access/deny mode
2320 	 * @param[in] new_openflags Current access/deny mode
2321 	 */
2322 	
2323 	void update_share_counters(struct fsal_share *share,
2324 				   fsal_openflags_t old_openflags,
2325 				   fsal_openflags_t new_openflags)
2326 	{
2327 		int access_read_inc =
2328 			((int)(new_openflags & FSAL_O_READ) != 0) -
2329 			((int)(old_openflags & FSAL_O_READ) != 0);
2330 	
2331 		int access_write_inc =
2332 			((int)(new_openflags & FSAL_O_WRITE) != 0) -
2333 			((int)(old_openflags & FSAL_O_WRITE) != 0);
2334 	
2335 		int deny_read_inc =
2336 			((int)(new_openflags & FSAL_O_DENY_READ) != 0) -
2337 			((int)(old_openflags & FSAL_O_DENY_READ) != 0);
2338 	
2339 		/* Combine both FSAL_O_DENY_WRITE and FSAL_O_DENY_WRITE_MAND */
2340 		int deny_write_inc =
2341 			((int)(new_openflags & FSAL_O_DENY_WRITE) != 0) -
2342 			((int)(old_openflags & FSAL_O_DENY_WRITE) != 0) +
2343 			((int)(new_openflags & FSAL_O_DENY_WRITE_MAND) != 0) -
2344 			((int)(old_openflags & FSAL_O_DENY_WRITE_MAND) != 0);
2345 	
2346 		int deny_write_mand_inc =
2347 			((int)(new_openflags & FSAL_O_DENY_WRITE_MAND) != 0) -
2348 			((int)(old_openflags & FSAL_O_DENY_WRITE_MAND) != 0);
2349 	
2350 		share->share_access_read += access_read_inc;
2351 		share->share_access_write += access_write_inc;
2352 		share->share_deny_read += deny_read_inc;
2353 		share->share_deny_write += deny_write_inc;
2354 		share->share_deny_write_mand += deny_write_mand_inc;
2355 	
2356 		LogFullDebug(COMPONENT_FSAL,
2357 			     "share counter: access_read %u, access_write %u, deny_read %u, deny_write %u, deny_write_v4 %u",
2358 			     share->share_access_read,
2359 			     share->share_access_write,
2360 			     share->share_deny_read,
2361 			     share->share_deny_write,
2362 			     share->share_deny_write_mand);
2363 	}
2364 	
2365 	/**
2366 	 * @brief Check for share conflict
2367 	 *
2368 	 * The caller is responsible for protecting the share.
2369 	 *
2370 	 * This function is NOT called if the caller holds a share reservation covering
2371 	 * the requested access.
2372 	 *
2373 	 * @param[in] share        File to query
2374 	 * @param[in] openflags    Desired access and deny mode
2375 	 * @param[in] bypass       Bypasses share_deny_read and share_deny_write but
2376 	 *                         not share_deny_write_mand
2377 	 *
2378 	 * @retval ERR_FSAL_SHARE_DENIED - a conflict occurred.
2379 	 *
2380 	 */
2381 	
2382 	fsal_status_t check_share_conflict(struct fsal_share *share,
2383 					   fsal_openflags_t openflags,
2384 					   bool bypass)
2385 	{
2386 		char *cause = "";
2387 	
2388 		if ((openflags & FSAL_O_READ) != 0
2389 		    && share->share_deny_read > 0
2390 		    && !bypass) {
2391 			cause = "access read denied by existing deny read";
2392 			goto out_conflict;
2393 		}
2394 	
2395 		if ((openflags & FSAL_O_WRITE) != 0
2396 		    && (share->share_deny_write_mand > 0 ||
2397 			(!bypass && share->share_deny_write > 0))) {
2398 			cause = "access write denied by existing deny write";
2399 			goto out_conflict;
2400 		}
2401 	
2402 		if ((openflags & FSAL_O_DENY_READ) != 0
2403 		    && share->share_access_read > 0) {
2404 			cause = "deny read denied by existing access read";
2405 			goto out_conflict;
2406 		}
2407 	
2408 		if (((openflags & FSAL_O_DENY_WRITE) != 0 ||
2409 		     (openflags & FSAL_O_DENY_WRITE_MAND) != 0)
2410 		    && share->share_access_write > 0) {
2411 			cause = "deny write denied by existing access write";
2412 			goto out_conflict;
2413 		}
2414 	
2415 		return fsalstat(ERR_FSAL_NO_ERROR, 0);
2416 	
2417 	 out_conflict:
2418 	
2419 		LogDebugAlt(COMPONENT_STATE, COMPONENT_FSAL,
2420 			    "Share conflict detected: %s openflags=%d bypass=%s",
2421 			    cause, (int) openflags,
2422 			    bypass ? "yes" : "no");
2423 	
2424 		LogFullDebugAlt(COMPONENT_STATE, COMPONENT_FSAL,
2425 				"share->share_deny_read=%d share->share_deny_write=%d share->share_access_read=%d share->share_access_write=%d",
2426 				share->share_deny_read, share->share_deny_write,
2427 				share->share_access_read, share->share_access_write);
2428 	
2429 		return fsalstat(ERR_FSAL_SHARE_DENIED, 0);
2430 	}
2431 	
2432 	/**
2433 	 * @brief Check two shares for conflict and merge.
2434 	 *
2435 	 * The caller is responsible for protecting the share.
2436 	 *
2437 	 * When two object handles are merged that both contain shares, we must
2438 	 * check if the duplicate has a share conflict with the original. If
2439 	 * so, we will return ERR_FSAL_SHARE_DENIED.
2440 	 *
2441 	 * @param[in] orig_share   Original share
2442 	 * @param[in] dupe_share   Duplicate share
2443 	 *
2444 	 * @retval ERR_FSAL_SHARE_DENIED - a conflict occurred.
2445 	 *
2446 	 */
2447 	
2448 	fsal_status_t merge_share(struct fsal_share *orig_share,
2449 				  struct fsal_share *dupe_share)
2450 	{
2451 		char *cause = "";
2452 	
2453 		if (dupe_share->share_access_read > 0 &&
2454 		    orig_share->share_deny_read > 0) {
2455 			cause = "access read denied by existing deny read";
2456 			goto out_conflict;
2457 		}
2458 	
2459 		if (dupe_share->share_deny_read > 0 &&
2460 		    orig_share->share_access_read > 0) {
2461 			cause = "deny read denied by existing access read";
2462 			goto out_conflict;
2463 		}
2464 	
2465 		/* When checking deny write, we ONLY need to look at share_deny_write
2466 		 * since it counts BOTH FSAL_O_DENY_WRITE and FSAL_O_DENY_WRITE_MAND.
2467 		 */
2468 		if (dupe_share->share_access_write > 0 &&
2469 		    orig_share->share_deny_write > 0) {
2470 			cause = "access write denied by existing deny write";
2471 			goto out_conflict;
2472 		}
2473 	
2474 		if (dupe_share->share_deny_write > 0 &&
2475 		    orig_share->share_access_write > 0) {
2476 			cause = "deny write denied by existing access write";
2477 			goto out_conflict;
2478 		}
2479 	
2480 		/* Now that we are ok, merge the share counters in the original */
2481 		orig_share->share_access_read += dupe_share->share_access_read;
2482 		orig_share->share_access_write += dupe_share->share_access_write;
2483 		orig_share->share_deny_read += dupe_share->share_deny_read;
2484 		orig_share->share_deny_write += dupe_share->share_deny_write;
2485 		orig_share->share_deny_write_mand += dupe_share->share_deny_write_mand;
2486 	
2487 		return fsalstat(ERR_FSAL_NO_ERROR, 0);
2488 	
2489 	 out_conflict:
2490 	
2491 		LogDebug(COMPONENT_STATE, "Share conflict detected: %s", cause);
2492 	
2493 		return fsalstat(ERR_FSAL_SHARE_DENIED, 0);
2494 	}
2495 	
2496 	/**
2497 	 * @brief Reopen the fd associated with the object handle.
2498 	 *
2499 	 * This function assures that the fd is open in the mode requested. If
2500 	 * the fd was already open, it closes it and reopens with the OR of the
2501 	 * requested modes.
2502 	 *
2503 	 * This function will return with the object handle lock held for read
2504 	 * if successful, except in the case where a temporary file descriptor is
2505 	 * in use because of a conflict with another thread. By not holding the
2506 	 * lock in that case, it may allow yet a third thread to open the global
2507 	 * file descriptor in a usable mode reducing the use of temporary file
2508 	 * descriptors.
2509 	 *
2510 	 * On calling, out_fd must point to a temporary fd. On return, out_fd
2511 	 * will either still point to the temporary fd, which has now been opened
2512 	 * and must be closed when done, or it will point to the object handle's
2513 	 * global fd, which should be left open.
2514 	 *
2515 	 * Optionally, out_fd can be NULL in which case a file is not actually
2516 	 * opened, in this case, all that actually happens is the share reservation
2517 	 * check (which may result in the lock being held).
2518 	 *
2519 	 * If openflags is FSAL_O_ANY, the caller will utilize the global file
2520 	 * descriptor if it is open, otherwise it will use a temporary file descriptor.
2521 	 * The primary use of this is to not open long lasting global file descriptors
2522 	 * for getattr and setattr calls. The other users of FSAL_O_ANY are NFSv3 LOCKT
2523 	 * for which this behavior is also desireable and NFSv3 UNLOCK where there
2524 	 * SHOULD be an open file descriptor attached to state, but if not, a temporary
2525 	 * file descriptor will work fine (and the resulting unlock won't do anything
2526 	 * since we just opened the temporary file descriptor).
2527 	 *
2528 	 * @param[in]  obj_hdl     File on which to operate
2529 	 * @param[in]  check_share Indicates we must check for share conflict
2530 	 * @param[in]  bypass         If state doesn't indicate a share reservation,
2531 	 *                               bypass any deny read
2532 	 * @param[in] bypass       If check_share is true, indicates to bypass
2533 	 *                         share_deny_read and share_deny_write but
2534 	 *                         not share_deny_write_mand
2535 	 * @param[in]  openflags   Mode for open
2536 	 * @param[in]  my_fd       The file descriptor associated with the object
2537 	 * @param[in]  share       The fsal_share associated with the object
2538 	 * @param[in]  open_func   Function to open a file descriptor
2539 	 * @param[in]  close_func  Function to close a file descriptor
2540 	 * @param[in,out] out_fd   File descriptor that is to be used
2541 	 * @param[out] has_lock    Indicates that obj_hdl->lock is held read
2542 	 * @param[out] closefd     Indicates that file descriptor must be closed
2543 	 *
2544 	 * @return FSAL status.
2545 	 */
2546 	
2547 	fsal_status_t fsal_reopen_obj(struct fsal_obj_handle *obj_hdl,
2548 				      bool check_share,
2549 				      bool bypass,
2550 				      fsal_openflags_t openflags,
2551 				      struct fsal_fd *my_fd,
2552 				      struct fsal_share *share,
2553 				      fsal_open_func open_func,
2554 				      fsal_close_func close_func,
2555 				      struct fsal_fd **out_fd,
2556 				      bool *has_lock,
2557 				      bool *closefd)
2558 	{
2559 		fsal_status_t status = {ERR_FSAL_NO_ERROR, 0};
2560 		bool retried = false;
2561 		fsal_openflags_t try_openflags;
2562 		int rc;
2563 	
2564 		*closefd = false;
2565 	
2566 		/* Take read lock on object to protect file descriptor.
2567 		 * We only take a read lock because we are not changing the
2568 		 * state of the file descriptor.
2569 		 */
(1) Event cond_true: Condition "rc == 0", taking true branch.
(2) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(3) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(4) Event if_fallthrough: Falling through to end of if statement.
(5) Event if_end: End of if statement.
2570 		PTHREAD_RWLOCK_rdlock(&obj_hdl->obj_lock);
2571 	
(6) Event cond_true: Condition "check_share", taking true branch.
2572 		if (check_share) {
2573 			/* Note we will check again if we drop and re-acquire the lock
2574 			 * just to be on the safe side.
2575 			 */
2576 			status = check_share_conflict(share, openflags, bypass);
2577 	
(7) Event cond_false: Condition "!(status.major == ERR_FSAL_NO_ERROR)", taking false branch.
2578 			if (FSAL_IS_ERROR(status)) {
2579 				PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
2580 				LogDebug(COMPONENT_FSAL,
2581 					 "check_share_conflict failed with %s",
2582 					 msg_fsal_err(status.major));
2583 				*has_lock = false;
2584 				return status;
(8) Event if_end: End of if statement.
2585 			}
2586 		}
2587 	
(9) Event cond_false: Condition "out_fd == NULL", taking false branch.
2588 		if (out_fd == NULL) {
2589 			/* We are just checking share reservation if at all.
2590 			 * There is no need to proceed, we either passed the
2591 			 * share check, or didn't need it. In either case, there
2592 			 * is no need to open a file.
2593 			 */
2594 			*has_lock = true;
2595 			return fsalstat(ERR_FSAL_NO_ERROR, 0);
(10) Event if_end: End of if statement.
2596 		}
2597 	
(61) Event label: Reached label "again".
2598 	again:
2599 	
(11) Event cond_true: Condition "!!(component_log_level[COMPONENT_FSAL] >= NIV_FULL_DEBUG)", taking true branch.
(12) Event cond_true: Condition "!!(component_log_level[COMPONENT_FSAL] >= NIV_FULL_DEBUG)", taking true branch.
(62) Event cond_true: Condition "!!(component_log_level[COMPONENT_FSAL] >= NIV_FULL_DEBUG)", taking true branch.
(63) Event cond_true: Condition "!!(component_log_level[COMPONENT_FSAL] >= NIV_FULL_DEBUG)", taking true branch.
2600 		LogFullDebug(COMPONENT_FSAL,
2601 			     "Open mode = %x, desired mode = %x",
2602 			     (int) my_fd->openflags,
2603 			     (int) openflags);
2604 	
(13) Event cond_true: Condition "not_open_usable(my_fd->openflags, openflags)", taking true branch.
(64) Event cond_false: Condition "not_open_usable(my_fd->openflags, openflags)", taking false branch.
2605 		if (not_open_usable(my_fd->openflags, openflags)) {
2606 	
2607 			/* Drop the read lock */
(14) Event cond_true: Condition "rc == 0", taking true branch.
(15) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(16) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(17) Event if_fallthrough: Falling through to end of if statement.
(18) Event if_end: End of if statement.
2608 			PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
2609 	
(19) Event cond_false: Condition "openflags == 32", taking false branch.
2610 			if (openflags == FSAL_O_ANY) {
2611 				/* If caller is looking for any open descriptor, don't
2612 				 * bother trying to open global file descriptor if it
2613 				 * isn't already open, just go ahead an open a temporary
2614 				 * file descriptor.
2615 				 */
2616 				LogDebug(COMPONENT_FSAL,
2617 					 "Open in FSAL_O_ANY mode failed, just open temporary file descriptor.");
2618 	
2619 				/* Although the global file descriptor isn't "busy" (we
2620 				 * can't acquire a write lock, re-use of EBUSY in this
2621 				 * case simplifies the code below.
2622 				 */
2623 				rc = EBUSY;
(20) Event else_branch: Reached else branch.
(21) Event cond_false: Condition "retried", taking false branch.
2624 			} else if (retried) {
2625 				/* Since we drop write lock for 'obj_hdl->obj_lock'
2626 				 * and acquire read lock for 'obj_hdl->obj_lock' after
2627 				 * opening the global file descriptor, some other
2628 				 * thread could have closed the file causing
2629 				 * verification of 'openflags' to fail.
2630 				 *
2631 				 * We will now attempt to just provide a temporary
2632 				 * file descriptor. EBUSY is sort of true...
2633 				 */
2634 				LogDebug(COMPONENT_FSAL,
2635 					 "Retry failed.");
2636 				rc = EBUSY;
(22) Event else_branch: Reached else branch.
2637 			} else {
2638 				/* Switch to write lock on object to protect file
2639 				 * descriptor.
2640 				 * By using trylock, we don't block if another thread
2641 				 * is using the file descriptor right now. In that
2642 				 * case, we just open a temporary file descriptor.
2643 				 *
2644 				 * This prevents us from blocking for the duration of
2645 				 * an I/O request.
2646 				 */
2647 				rc = pthread_rwlock_trywrlock(&obj_hdl->obj_lock);
2648 			}
2649 	
(23) Event cond_false: Condition "rc == 16", taking false branch.
2650 			if (rc == EBUSY) {
2651 				/* Someone else is using the file descriptor or it
2652 				 * isn't open at all and the caller is looking for
2653 				 * any mode of open so a temporary file descriptor will
2654 				 * work fine.
2655 				 *
2656 				 * Just provide a temporary file descriptor.
2657 				 * We still take a read lock so we can protect the
2658 				 * share reservation for the duration of the caller's
2659 				 * operation if we needed to check.
2660 				 */
2661 				if (check_share) {
2662 					PTHREAD_RWLOCK_rdlock(&obj_hdl->obj_lock);
2663 	
2664 					status = check_share_conflict(share,
2665 								      openflags,
2666 								      bypass);
2667 	
2668 					if (FSAL_IS_ERROR(status)) {
2669 						PTHREAD_RWLOCK_unlock(
2670 								&obj_hdl->obj_lock);
2671 						LogDebug(COMPONENT_FSAL,
2672 							 "check_share_conflict failed with %s",
2673 							 msg_fsal_err(status.major));
2674 						*has_lock = false;
2675 						return status;
2676 					}
2677 				}
2678 	
2679 				status = open_func(obj_hdl, openflags, *out_fd);
2680 	
2681 				if (FSAL_IS_ERROR(status)) {
2682 					if (check_share)
2683 						PTHREAD_RWLOCK_unlock(
2684 								&obj_hdl->obj_lock);
2685 					*has_lock = false;
2686 					return status;
2687 				}
2688 	
2689 				/* Return the temp fd, with the lock only held if
2690 				 * share reservations were checked.
2691 				 */
2692 				*closefd = true;
2693 				*has_lock = check_share;
2694 	
2695 				return fsalstat(ERR_FSAL_NO_ERROR, 0);
2696 	
(24) Event else_branch: Reached else branch.
(25) Event cond_false: Condition "rc != 0", taking false branch.
2697 			} else if (rc != 0) {
2698 				LogCrit(COMPONENT_RW_LOCK,
2699 					"Error %d, write locking %p", rc, obj_hdl);
2700 				abort();
(26) Event if_end: End of if statement.
2701 			}
2702 	
(27) Event cond_true: Condition "check_share", taking true branch.
2703 			if (check_share) {
2704 				status = check_share_conflict(share, openflags, bypass);
2705 	
(28) Event cond_false: Condition "!(status.major == ERR_FSAL_NO_ERROR)", taking false branch.
2706 				if (FSAL_IS_ERROR(status)) {
2707 					PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
2708 					LogDebug(COMPONENT_FSAL,
2709 						 "check_share_conflict failed with %s",
2710 						 msg_fsal_err(status.major));
2711 					*has_lock = false;
2712 					return status;
(29) Event if_end: End of if statement.
2713 				}
2714 			}
2715 	
(30) Event cond_true: Condition "!!(component_log_level[COMPONENT_FSAL] >= NIV_FULL_DEBUG)", taking true branch.
(31) Event cond_true: Condition "!!(component_log_level[COMPONENT_FSAL] >= NIV_FULL_DEBUG)", taking true branch.
2716 			LogFullDebug(COMPONENT_FSAL,
2717 				     "Open mode = %x, desired mode = %x",
2718 				     (int) my_fd->openflags,
2719 				     (int) openflags);
2720 	
(32) Event cond_true: Condition "not_open_usable(my_fd->openflags, openflags)", taking true branch.
2721 			if (not_open_usable(my_fd->openflags, openflags)) {
(33) Event cond_true: Condition "my_fd->openflags != 0", taking true branch.
2722 				if (my_fd->openflags != FSAL_O_CLOSED) {
2723 					ssize_t count;
2724 	
2725 					/* Add desired mode to existing mode. */
2726 					try_openflags = openflags | my_fd->openflags;
2727 	
2728 					/* Now close the already open descriptor. */
2729 					status = close_func(obj_hdl, my_fd);
2730 	
(34) Event cond_false: Condition "!(status.major == ERR_FSAL_NO_ERROR)", taking false branch.
2731 					if (FSAL_IS_ERROR(status)) {
2732 						PTHREAD_RWLOCK_unlock(
2733 								&obj_hdl->obj_lock);
2734 						LogDebug(COMPONENT_FSAL,
2735 							 "close_func failed with %s",
2736 							 msg_fsal_err(status.major));
2737 						*has_lock = false;
2738 						return status;
(35) Event if_end: End of if statement.
2739 					}
2740 					count = atomic_dec_size_t(&open_fd_count);
(36) Event cond_false: Condition "count < 0", taking false branch.
2741 					if (count < 0) {
2742 						LogCrit(COMPONENT_FSAL,
2743 						    "open_fd_count is negative: %zd",
2744 						    count);
(37) Event if_end: End of if statement.
2745 					}
(38) Event if_fallthrough: Falling through to end of if statement.
2746 				} else if (openflags == FSAL_O_ANY) {
2747 					try_openflags = FSAL_O_READ;
2748 				} else {
2749 					try_openflags = openflags;
(39) Event if_end: End of if statement.
2750 				}
2751 	
(40) Event cond_true: Condition "!!(component_log_level[COMPONENT_FSAL] >= NIV_FULL_DEBUG)", taking true branch.
(41) Event cond_true: Condition "!!(component_log_level[COMPONENT_FSAL] >= NIV_FULL_DEBUG)", taking true branch.
2752 				LogFullDebug(COMPONENT_FSAL,
2753 					     "try_openflags = %x",
2754 					     try_openflags);
2755 	
(42) Event cond_false: Condition "!mdcache_lru_fds_available()", taking false branch.
2756 				if (!mdcache_lru_fds_available()) {
2757 					PTHREAD_RWLOCK_unlock(
2758 							&obj_hdl->obj_lock);
2759 					*has_lock = false;
2760 					/* This seems the best idea, let the
2761 					 * client try again later after the reap.
2762 					 */
2763 					return fsalstat(ERR_FSAL_DELAY, 0);
(43) Event if_end: End of if statement.
2764 				}
2765 	
2766 				/* Actually open the file */
2767 				status = open_func(obj_hdl, try_openflags, my_fd);
2768 	
(44) Event cond_false: Condition "!(status.major == ERR_FSAL_NO_ERROR)", taking false branch.
2769 				if (FSAL_IS_ERROR(status)) {
2770 					PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
2771 					LogDebug(COMPONENT_FSAL,
2772 						 "open_func failed with %s",
2773 						 msg_fsal_err(status.major));
2774 					*has_lock = false;
2775 					return status;
(45) Event if_end: End of if statement.
2776 				}
2777 	
2778 				(void) atomic_inc_size_t(&open_fd_count);
2779 			}
2780 	
2781 			/* Ok, now we should be in the correct mode.
2782 			 * Switch back to read lock and try again.
2783 			 * We don't want to hold the write lock because that would
2784 			 * block other users of the file descriptor.
2785 			 * Since we dropped the lock, we need to verify mode is still'
2786 			 * good after we re-aquire the read lock, thus the retry.
2787 			 */
(46) Event cond_true: Condition "rc == 0", taking true branch.
(47) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(48) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(49) Event if_fallthrough: Falling through to end of if statement.
(50) Event if_end: End of if statement.
2788 			PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
(51) Event lock: "pthread_rwlock_rdlock" locks "obj_hdl->obj_lock".
(52) Event cond_true: Condition "rc == 0", taking true branch.
(53) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(54) Event cond_true: Condition "!!(component_log_level[COMPONENT_RW_LOCK] >= NIV_FULL_DEBUG)", taking true branch.
(55) Event if_fallthrough: Falling through to end of if statement.
(56) Event if_end: End of if statement.
Also see events: [missing_unlock]
2789 			PTHREAD_RWLOCK_rdlock(&obj_hdl->obj_lock);
2790 			retried = true;
2791 	
(57) Event cond_true: Condition "check_share", taking true branch.
2792 			if (check_share) {
2793 				status = check_share_conflict(share, openflags, bypass);
2794 	
(58) Event cond_false: Condition "!(status.major == ERR_FSAL_NO_ERROR)", taking false branch.
2795 				if (FSAL_IS_ERROR(status)) {
2796 					PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
2797 					LogDebug(COMPONENT_FSAL,
2798 						 "check_share_conflict failed with %s",
2799 						 msg_fsal_err(status.major));
2800 					*has_lock = false;
2801 					return status;
(59) Event if_end: End of if statement.
2802 				}
2803 			}
(60) Event goto: Jumping to label "again".
2804 			goto again;
(65) Event if_end: End of if statement.
2805 		}
2806 	
2807 		/* Return the global fd, with the lock held. */
2808 		*out_fd = my_fd;
2809 		*has_lock = true;
2810 	
(66) Event missing_unlock: Returning without unlocking "obj_hdl->obj_lock".
Also see events: [lock]
2811 		return fsalstat(ERR_FSAL_NO_ERROR, 0);
2812 	}
2813 	
2814 	/**
2815 	 * @brief Find a useable file descriptor for a regular file.
2816 	 *
2817 	 * This function specifically does NOT return with the obj_handle's lock
2818 	 * held if the fd associated with a state_t is being used. These fds are
2819 	 * considered totally separate from the global fd and don't need protection
2820 	 * and should not interfere with other operations on the object.
2821 	 *
2822 	 * Optionally, out_fd can be NULL in which case a file is not actually
2823 	 * opened, in this case, all that actually happens is the share reservation
2824 	 * check (which may result in the lock being held).
2825 	 *
2826 	 * Note that FSAL_O_ANY may be passed on to fsal_reopen_obj, see the
2827 	 * documentation of that function for the implications.
2828 	 *
2829 	 * @param[in,out] out_fd         File descriptor that is to be used
2830 	 * @param[in]     obj_hdl        File on which to operate
2831 	 * @param[in]     obj_fd         The file descriptor associated with the object
2832 	 * @param[in]     bypass         If state doesn't indicate a share reservation,
2833 	 *                               bypass any deny read
2834 	 * @param[in]     state          state_t to use for this operation
2835 	 * @param[in]     openflags      Mode for open
2836 	 * @param[in]     open_func      Function to open a file descriptor
2837 	 * @param[in]     close_func     Function to close a file descriptor
2838 	 * @param[out]    has_lock       Indicates that obj_hdl->obj_lock is held read
2839 	 * @param[out]    closefd        Indicates that file descriptor must be closed
2840 	 * @param[in]     open_for_locks Indicates file is open for locks
2841 	 * @param[out]    reusing_open_state_fd Indicates whether already opened fd
2842 	 *					can be reused
2843 	 *
2844 	 * @return FSAL status.
2845 	 */
2846 	
2847 	fsal_status_t fsal_find_fd(struct fsal_fd **out_fd,
2848 				   struct fsal_obj_handle *obj_hdl,
2849 				   struct fsal_fd *obj_fd,
2850 				   struct fsal_share *share,
2851 				   bool bypass,
2852 				   struct state_t *state,
2853 				   fsal_openflags_t openflags,
2854 				   fsal_open_func open_func,
2855 				   fsal_close_func close_func,
2856 				   bool *has_lock,
2857 				   bool *closefd,
2858 				   bool open_for_locks,
2859 				   bool *reusing_open_state_fd)
2860 	{
2861 		fsal_status_t status = {ERR_FSAL_NO_ERROR, 0};
2862 		struct fsal_fd *state_fd;
2863 	
2864 		if (state == NULL)
2865 			goto global;
2866 	
2867 		/* Check if we can use the fd in the state */
2868 		state_fd = (struct fsal_fd *) (state + 1);
2869 	
2870 		LogFullDebug(COMPONENT_FSAL,
2871 			     "state_fd->openflags = %d openflags = %d%s",
2872 			     state_fd->openflags, openflags,
2873 			     open_for_locks ? " Open For Locks" : "");
2874 	
2875 		if (open_correct(state_fd->openflags, openflags)) {
2876 			/* It was valid, return it.
2877 			 * Since we found a valid fd in the state, no need to
2878 			 * check deny modes.
2879 			 */
2880 			LogFullDebug(COMPONENT_FSAL, "Use state_fd %p", state_fd);
2881 			if (out_fd)
2882 				*out_fd = state_fd;
2883 			*has_lock = false;
2884 			return status;
2885 		}
2886 	
2887 		if (open_for_locks) {
2888 			if (state_fd->openflags != FSAL_O_CLOSED) {
2889 				LogCrit(COMPONENT_FSAL,
2890 					"Conflicting open, can not re-open fd with locks");
2891 				return fsalstat(posix2fsal_error(EINVAL), EINVAL);
2892 			}
2893 	
2894 			/* This is being opened for locks, we will not be able to
2895 			 * re-open so open for read/write. If that fails permission
2896 			 * check and openstate is available, retry with that state's
2897 			 * access mode.
2898 			 */
2899 			openflags = FSAL_O_RDWR;
2900 	
2901 			status = open_func(obj_hdl, openflags, state_fd);
2902 	
2903 			if (status.major == ERR_FSAL_ACCESS &&
2904 			    state->state_data.lock.openstate != NULL) {
2905 				/* Got an EACCESS and openstate is available, try
2906 				 * again with it's openflags.
2907 				 */
2908 				struct fsal_fd *related_fd = (struct fsal_fd *)
2909 						(state->state_data.lock.openstate + 1);
2910 	
2911 				openflags = related_fd->openflags & FSAL_O_RDWR;
2912 	
2913 				status = open_func(obj_hdl, openflags, state_fd);
2914 			}
2915 	
2916 			if (FSAL_IS_ERROR(status)) {
2917 				LogCrit(COMPONENT_FSAL,
2918 					"Open for locking failed for access %s",
2919 					openflags == FSAL_O_RDWR ? "Read/Write"
2920 					: openflags == FSAL_O_READ ? "Read"
2921 					: "Write");
2922 			} else {
2923 				LogFullDebug(COMPONENT_FSAL,
2924 					     "Opened state_fd %p", state_fd);
2925 				*out_fd = state_fd;
2926 			}
2927 	
2928 			*has_lock = false;
2929 			return status;
2930 		}
2931 	
2932 		/* Check if there is a related state, in which case, can we use it's
2933 		 * fd (this will support FSALs that have an open file per open state
2934 		 * but don't bother with opening a separate file for the lock state).
2935 		 */
2936 		if ((state->state_type == STATE_TYPE_LOCK ||
2937 		     state->state_type == STATE_TYPE_NLM_LOCK) &&
2938 		    state->state_data.lock.openstate != NULL) {
2939 			struct fsal_fd *related_fd = (struct fsal_fd *)
2940 					(state->state_data.lock.openstate + 1);
2941 	
2942 			LogFullDebug(COMPONENT_FSAL,
2943 				     "related_fd->openflags = %d openflags = %d",
2944 				     related_fd->openflags, openflags);
2945 	
2946 			if (open_correct(related_fd->openflags, openflags)) {
2947 				/* It was valid, return it.
2948 				 * Since we found a valid fd in the open state, no
2949 				 * need to check deny modes.
2950 				 */
2951 				LogFullDebug(COMPONENT_FSAL,
2952 					     "Use related_fd %p", related_fd);
2953 				if (out_fd) {
2954 					*out_fd = related_fd;
2955 					/* The associated open state has an open fd,
2956 					 * however some FSALs can not use it and must
2957 					 * need to dup the fd into the lock state
2958 					 * instead. So to signal this to the caller
2959 					 * function the following flag
2960 					 */
2961 					*reusing_open_state_fd = true;
2962 				}
2963 	
2964 				*has_lock = false;
2965 				return status;
2966 			}
2967 		}
2968 	
2969 	 global:
2970 	
2971 		/* No useable state_t so return the global file descriptor. */
2972 		LogFullDebug(COMPONENT_FSAL,
2973 			     "Use global fd openflags = %x",
2974 			     openflags);
2975 	
2976 		/* Make sure global is open as necessary otherwise return a
2977 		 * temporary file descriptor. Check share reservation if not
2978 		 * opening FSAL_O_ANY.
2979 		 */
2980 		return fsal_reopen_obj(obj_hdl, openflags != FSAL_O_ANY, bypass,
2981 				       openflags, obj_fd, share, open_func, close_func,
2982 				       out_fd, has_lock, closefd);
2983 	}
2984 	
2985 	/**
2986 	 * @brief Check the exclusive create verifier for a file.
2987 	 *
2988 	 * The default behavior is to check verifier against atime and mtime.
2989 	 *
2990 	 * @param[in] st          POSIX attributes for the file (from stat)
2991 	 * @param[in] verifier    Verifier to use for exclusive create
2992 	 *
2993 	 * @retval true if verifier matches
2994 	 */
2995 	
2996 	bool check_verifier_stat(struct stat *st, fsal_verifier_t verifier)
2997 	{
2998 		uint32_t verf_hi = 0, verf_lo = 0;
2999 	
3000 		memcpy(&verf_hi,
3001 		       verifier,
3002 		       sizeof(uint32_t));
3003 		memcpy(&verf_lo,
3004 		       verifier + sizeof(uint32_t),
3005 		       sizeof(uint32_t));
3006 	
3007 		LogFullDebug(COMPONENT_FSAL,
3008 			     "Passed verifier %"PRIx32" %"PRIx32
3009 			     " file verifier %"PRIx32" %"PRIx32,
3010 			     verf_hi, verf_lo,
3011 			     (uint32_t) st->st_atim.tv_sec,
3012 			     (uint32_t) st->st_mtim.tv_sec);
3013 	
3014 		return st->st_atim.tv_sec == verf_hi &&
3015 		       st->st_mtim.tv_sec == verf_lo;
3016 	}
3017 	
3018 	/**
3019 	 * @brief Check the exclusive create verifier for a file.
3020 	 *
3021 	 * The default behavior is to check verifier against atime and mtime.
3022 	 *
3023 	 * @param[in] attrlist    Attributes for the file
3024 	 * @param[in] verifier    Verifier to use for exclusive create
3025 	 *
3026 	 * @retval true if verifier matches
3027 	 */
3028 	
3029 	bool check_verifier_attrlist(struct attrlist *attrs, fsal_verifier_t verifier)
3030 	{
3031 		uint32_t verf_hi = 0, verf_lo = 0;
3032 	
3033 		memcpy(&verf_hi,
3034 		       verifier,
3035 		       sizeof(uint32_t));
3036 		memcpy(&verf_lo,
3037 		       verifier + sizeof(uint32_t),
3038 		       sizeof(uint32_t));
3039 	
3040 		LogFullDebug(COMPONENT_FSAL,
3041 			     "Passed verifier %"PRIx32" %"PRIx32
3042 			     " file verifier %"PRIx32" %"PRIx32,
3043 			     verf_hi, verf_lo,
3044 			     (uint32_t) attrs->atime.tv_sec,
3045 			     (uint32_t) attrs->mtime.tv_sec);
3046 	
3047 		return attrs->atime.tv_sec == verf_hi &&
3048 		       attrs->mtime.tv_sec == verf_lo;
3049 	}
3050 	
3051 	/**
3052 	 * @brief Common is_referral routine for FSALs that use the special mode
3053 	 *
3054 	 * @param[in]     obj_hdl       Handle on which to operate
3055 	 * @param[in|out] attrs         Attributes of the handle
3056 	 * @param[in]     cache_attrs   Cache the received attrs
3057 	 *
3058 	 * Most FSALs don't support referrals, but those that do often use a special
3059 	 * mode bit combination on a directory for a junction. This routine tests for
3060 	 * that and returns true if it is a referral.
3061 	 */
3062 	bool fsal_common_is_referral(struct fsal_obj_handle *obj_hdl,
3063 				     struct attrlist *attrs, bool cache_attrs)
3064 	{
3065 		LogDebug(COMPONENT_FSAL, "Checking attrs for referral"
3066 			 ", handle: %p, valid_mask: %" PRIx64
3067 			 ", request_mask: %" PRIx64 ", supported: %" PRIx64,
3068 			 obj_hdl, attrs->valid_mask,
3069 			 attrs->request_mask, attrs->supported);
3070 	
3071 		if ((attrs->valid_mask & (ATTR_TYPE | ATTR_MODE)) == 0) {
3072 			/* Required attributes are not available, need to fetch them */
3073 			fsal_status_t status = {ERR_FSAL_NO_ERROR, 0};
3074 	
3075 			attrs->request_mask |= (ATTR_TYPE | ATTR_MODE);
3076 	
3077 			status = obj_hdl->obj_ops->getattrs(obj_hdl, attrs);
3078 			if (FSAL_IS_ERROR(status)) {
3079 				LogEvent(COMPONENT_FSAL,
3080 					 "Failed to get attrs for referral, "
3081 					 "handle: %p, valid_mask: %" PRIx64
3082 					 ", request_mask: %" PRIx64
3083 					 ", supported: %" PRIx64,
3084 					 obj_hdl, attrs->valid_mask,
3085 					 attrs->request_mask, attrs->supported);
3086 				return false;
3087 			}
3088 		}
3089 	
3090 		if (!fsal_obj_handle_is(obj_hdl, DIRECTORY))
3091 			return false;
3092 	
3093 		if (!is_sticky_bit_set(obj_hdl, attrs))
3094 			return false;
3095 	
3096 		LogDebug(COMPONENT_FSAL, "Referral found for handle: %p", obj_hdl);
3097 		return true;
3098 	}
3099 	
3100 	/** @} */
3101