1    	/*
2    	 * vim:noexpandtab:shiftwidth=8:tabstop=8:
3    	 *
4    	 * Copyright CEA/DAM/DIF  (2008)
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 License
11   	 * as published by the Free Software Foundation; either version 3 of
12   	 * 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   	 * @file    nfs4_op_open.c
29   	 * @brief   NFS4_OP_OPEN
30   	 *
31   	 * Function implementing the NFS4_OP_OPEN operation and support code.
32   	 */
33   	
34   	#include "config.h"
35   	#include "log.h"
36   	#include "fsal.h"
37   	#include "nfs_core.h"
38   	#include "nfs_exports.h"
39   	#include "sal_functions.h"
40   	#include "nfs_proto_functions.h"
41   	#include "nfs_proto_tools.h"
42   	#include "nfs_convert.h"
43   	#include "fsal_convert.h"
44   	#include "nfs_creds.h"
45   	#include "export_mgr.h"
46   	#include "nfs_rpc_callback.h"
47   	
48   	static const char *open_tag = "OPEN";
49   	
50   	/**
51   	 * @brief Copy an OPEN result
52   	 *
53   	 * This function copies an open result to the supplied destination.
54   	 *
55   	 * @param[out] res_dst Buffer to which to copy the result
56   	 * @param[in]  res_src The result to copy
57   	 */
58   	void nfs4_op_open_CopyRes(OPEN4res *res_dst, OPEN4res *res_src)
59   	{
60   		res_dst->OPEN4res_u.resok4.attrset = res_src->OPEN4res_u.resok4.attrset;
61   	}
62   	
63   	/**
64   	 * @brief Create an NFSv4 filehandle
65   	 *
66   	 * This function creates an NFSv4 filehandle from the supplied file
67   	 * and sets it to be the current filehandle.
68   	 *
69   	 * @note This calls @ref set_current_entry which takes a ref; this then drops
70   	 * it's ref.
71   	 *
72   	 * @param[in,out] data   Compound's data
73   	 * @param[in]     obj    File
74   	 *
75   	 * @retval NFS4_OK on success.
76   	 * @retval Valid errors for NFS4_OP_OPEN.
77   	 */
78   	
79   	static nfsstat4 open4_create_fh(compound_data_t *data,
80   					struct fsal_obj_handle *obj,
81   					bool state_lock_held)
82   	{
83   		bool set_no_cleanup = false;
84   	
85   		/* Building a new fh */
86   		if (!nfs4_FSALToFhandle(false, &data->currentFH, obj,
87   						op_ctx->ctx_export)) {
88   			obj->obj_ops->put_ref(obj);
89   			return NFS4ERR_SERVERFAULT;
90   		}
91   	
92   		/* Update the current entry */
93   		set_current_entry(data, obj);
94   	
95   		if (state_lock_held) {
96   			/* Make sure we don't do cleanup holding the state_lock.
97   			 * there will be an additional put_ref without the state_lock
98   			 * being held.
99   			 */
100  			obj->state_hdl->no_cleanup = true;
101  			set_no_cleanup = true;
102  		}
103  	
104  		/* Put our ref */
105  		obj->obj_ops->put_ref(obj);
106  	
107  		if (set_no_cleanup) {
108  			/* And clear the no_cleanup we set above. */
109  			obj->state_hdl->no_cleanup = false;
110  		}
111  	
112  		return NFS4_OK;
113  	}
114  	
115  	/**
116  	 * @brief Validate claim type
117  	 *
118  	 * Check that the claim type specified is allowed and return the
119  	 * appropriate error code if not.
120  	 *
121  	 * @param[in]  data         Compound's data
122  	 * @param[in]  claim        Claim type
123  	 * @param[out] grace_ref    Did this function acquire a grace reference?
124  	 *
125  	 * @retval NFS4_OK claim is valid.
126  	 * @retval NFS4ERR_GRACE new open not allowed in grace period.
127  	 * @retval NFS4ERR_NO_GRACE reclaim not allowed after grace period or
128  	 *         reclaim complete.
129  	 * @retval NFS4ERR_NOTSUPP claim type not supported by minor version.
130  	 * @retval NFS4ERR_INVAL unknown claim type.
131  	 */
132  	
133  	static nfsstat4 open4_validate_claim(compound_data_t *data,
134  					     open_claim_type4 claim,
135  					     nfs_client_id_t *clientid,
136  					     bool *grace_ref)
137  	{
138  		/* Return code */
139  		nfsstat4 status = NFS4_OK;
140  		/* does this claim require a grace period? */
141  		bool want_grace = false;
142  		/* do we need a reference on the current state of grace? */
143  		bool take_ref = !op_ctx->fsal_export->exp_ops.fs_supports(
144  						op_ctx->fsal_export, fso_grace_method);
145  	
146  		switch (claim) {
147  		case CLAIM_NULL:
148  			if ((data->minorversion > 0)
149  			    && !clientid->cid_cb.v41.cid_reclaim_complete)
150  				status = NFS4ERR_GRACE;
151  			break;
152  	
153  		case CLAIM_FH:
154  			if (data->minorversion == 0)
155  				status = NFS4ERR_NOTSUPP;
156  			break;
157  	
158  		case CLAIM_DELEGATE_PREV:
159  			status = NFS4ERR_NOTSUPP;
160  			break;
161  	
162  		case CLAIM_PREVIOUS:
163  			want_grace = true;
164  			if (!clientid->cid_allow_reclaim ||
165  			    ((data->minorversion > 0) &&
166  			    clientid->cid_cb.v41.cid_reclaim_complete))
167  				status = NFS4ERR_NO_GRACE;
168  			break;
169  	
170  		case CLAIM_DELEGATE_CUR:
171  			take_ref = false;
172  			break;
173  	
174  		case CLAIM_DELEG_CUR_FH:
175  			take_ref = false;
176  			if (data->minorversion == 0)
177  				status = NFS4ERR_NOTSUPP;
178  			break;
179  	
180  		case CLAIM_DELEG_PREV_FH:
181  			status = NFS4ERR_NOTSUPP;
182  			break;
183  	
184  		default:
185  			status = NFS4ERR_INVAL;
186  		}
187  	
188  		if (status == NFS4_OK) {
189  			if (take_ref) {
190  				if (nfs_get_grace_status(want_grace)) {
191  					*grace_ref = true;
192  				} else {
193  					status = want_grace ? NFS4ERR_NO_GRACE :
194  							      NFS4ERR_GRACE;
195  				}
196  			} else {
197  				*grace_ref = false;
198  			}
199  		}
200  		return status;
201  	}
202  	
203  	/**
204  	 * @brief Validate and create an open owner
205  	 *
206  	 * This function finds or creates an owner to be associated with the
207  	 * requested open state.
208  	 *
209  	 * @param[in]     arg      Arguments to OPEN4 operation
210  	 * @param[in,out] data     Compound's data
211  	 * @param[out]    res      Response to OPEN4 operation
212  	 * @param[in]     clientid Clientid record for this request
213  	 * @param[out]    owner    The found/created owner owner
214  	 *
215  	 * @return false if error or replay (res_OPEN4->status is already set),
216  	 *         true otherwise.
217  	 */
218  	
219  	bool open4_open_owner(struct nfs_argop4 *op, compound_data_t *data,
220  			      struct nfs_resop4 *res, nfs_client_id_t *clientid,
221  			      state_owner_t **owner)
222  	{
223  		/* Shortcut to open args */
224  		OPEN4args * const arg_OPEN4 = &(op->nfs_argop4_u.opopen);
225  		/* Shortcut to open args */
226  		OPEN4res * const res_OPEN4 = &(res->nfs_resop4_u.opopen);
227  		/* The parsed-out name of the open owner */
228  		state_nfs4_owner_name_t owner_name;
229  		/* Indicates if the owner is new */
230  		bool_t isnew;
231  		/* Return value of FSAL operations */
232  		fsal_status_t status = {0, 0};
233  		struct fsal_obj_handle *obj_lookup = NULL;
234  	
235  		/* Is this open_owner known? If so, get it so we can use
236  		 * replay cache
237  		 */
238  		convert_nfs4_open_owner(&arg_OPEN4->owner, &owner_name);
239  	
240  		/* If this open owner is not known yet, allocate and set up a new one */
241  		*owner = create_nfs4_owner(&owner_name,
242  					   clientid,
243  					   STATE_OPEN_OWNER_NFSV4,
244  					   NULL,
245  					   0,
246  					   &isnew,
247  					   CARE_ALWAYS, data->minorversion != 0);
248  	
249  		LogStateOwner("Open: ", *owner);
250  	
251  		if (*owner == NULL) {
252  			res_OPEN4->status = NFS4ERR_RESOURCE;
253  			LogEvent(COMPONENT_STATE,
254  				 "NFS4 OPEN returning NFS4ERR_RESOURCE for CLAIM_NULL (could not create NFS4 Owner");
255  			return false;
256  		}
257  	
258  		/* Seqid checking is only proper for reused NFSv4.0 owner */
259  		if (isnew || (data->minorversion != 0))
260  			return true;
261  	
262  		if (arg_OPEN4->seqid == 0) {
263  			LogDebug(COMPONENT_STATE,
264  				 "Previously known open_owner is used with seqid=0, ask the client to confirm it again");
265  			(*owner)->so_owner.so_nfs4_owner.so_confirmed = false;
266  			return true;
267  		}
268  	
269  		/* Check for replay */
270  		if (Check_nfs4_seqid(*owner,
271  				     arg_OPEN4->seqid,
272  				     op,
273  				     data->current_obj,
274  				     res,
275  				     open_tag)) {
276  			/* No replay */
277  			return true;
278  		}
279  	
280  		/* Response is setup for us and LogDebug told what was
281  		 * wrong.
282  		 *
283  		 * Or if this is a seqid replay, find the file entry
284  		 * and update currentFH
285  		 */
286  		if (res_OPEN4->status == NFS4_OK) {
287  			utf8string *utfile;
288  			open_claim4 *oc = &arg_OPEN4->claim;
289  			char *filename;
290  	
291  			/* Load up CLAIM_DELEGATE_CUR file */
292  	
293  			switch (oc->claim) {
294  			case CLAIM_NULL:
295  				utfile = &oc->open_claim4_u.file;
296  				break;
297  			case CLAIM_DELEGATE_CUR:
298  				utfile = &oc->open_claim4_u.delegate_cur_info.file;
299  				break;
300  			case CLAIM_DELEGATE_PREV:
301  			default:
302  				return false;
303  			}
304  			/* Check if filename is correct */
305  			res_OPEN4->status = nfs4_utf8string2dynamic(
306  						utfile, UTF8_SCAN_ALL, &filename);
307  	
308  			if (res_OPEN4->status != NFS4_OK)
309  				return false;
310  	
311  			status = fsal_lookup(data->current_obj,
312  					     filename,
313  					     &obj_lookup,
314  					     NULL);
315  	
316  			gsh_free(filename);
317  	
318  			if (obj_lookup == NULL) {
319  				res_OPEN4->status = nfs4_Errno_status(status);
320  				return false;
321  			}
322  			res_OPEN4->status = open4_create_fh(data, obj_lookup, false);
323  		}
324  	
325  		return false;
326  	}
327  	
328  	/**
329  	 * @brief Check delegation claims while opening a file
330  	 *
331  	 * This function implements the CLAIM_DELEGATE_CUR claim.
332  	 *
333  	 * @param[in]     arg   OPEN4 arguments
334  	 * @param[in,out] data  Comopund's data
335  	 */
336  	static nfsstat4 open4_claim_deleg(OPEN4args *arg, compound_data_t *data)
337  	{
338  		open_claim_type4 claim = arg->claim.claim;
339  		stateid4 *rcurr_state;
340  		struct fsal_obj_handle *obj_lookup;
341  		const utf8string *utfname;
342  		char *filename;
343  		fsal_status_t fsal_status;
344  		nfsstat4 status;
345  		state_t *found_state = NULL;
346  	
347  		if (!(op_ctx->fsal_export->exp_ops.fs_supports(
348  						op_ctx->fsal_export, fso_delegations_w)
349  		      || op_ctx->fsal_export->exp_ops.fs_supports(
350  						op_ctx->fsal_export, fso_delegations_r))
351  		      ) {
352  			LogDebug(COMPONENT_STATE,
353  				 "NFS4 OPEN returning NFS4ERR_NOTSUPP for CLAIM_DELEGATE");
354  			return NFS4ERR_NOTSUPP;
355  		}
356  	
357  		assert((claim  == CLAIM_DELEGATE_CUR) ||
358  		       (claim == CLAIM_DELEG_CUR_FH));
359  	
360  		if (claim == CLAIM_DELEG_CUR_FH) {
361  			rcurr_state =
362  				&arg->claim.open_claim4_u.oc_delegate_stateid;
363  			goto find_state;
364  		}
365  	
366  		utfname = &arg->claim.open_claim4_u.delegate_cur_info.file;
367  		rcurr_state =
368  			&arg->claim.open_claim4_u.delegate_cur_info.delegate_stateid;
369  	
370  		LogDebug(COMPONENT_NFS_V4, "file name: %.*s",
371  			 utfname->utf8string_len, utfname->utf8string_val);
372  	
373  		/* Check if filename is correct */
374  		status = nfs4_utf8string2dynamic(utfname, UTF8_SCAN_ALL, &filename);
375  		if (status != NFS4_OK) {
376  			LogDebug(COMPONENT_NFS_V4, "Invalid filename");
377  			return status;
378  		}
379  	
380  		/* Does a file with this name already exist ? */
381  		fsal_status = fsal_lookup(data->current_obj, filename,
382  					  &obj_lookup, NULL);
383  	
384  		if (FSAL_IS_ERROR(fsal_status)) {
385  			LogDebug(COMPONENT_NFS_V4, "%s lookup failed.", filename);
386  			gsh_free(filename);
387  			return nfs4_Errno_status(fsal_status);
388  		}
389  		gsh_free(filename);
390  	
391  		status = open4_create_fh(data, obj_lookup, false);
392  		if (status != NFS4_OK) {
393  			LogDebug(COMPONENT_NFS_V4, "open4_create_fh failed");
394  			return status;
395  		}
396  	
397  	find_state:
398  		found_state = nfs4_State_Get_Pointer(rcurr_state->other);
399  	
400  		if (found_state == NULL) {
401  			LogDebug(COMPONENT_NFS_V4,
402  				 "state not found with CLAIM_DELEGATE_CUR");
403  			return NFS4ERR_BAD_STATEID;
404  		} else {
405  			/* FIXME: vet stateid here */
406  			if (isFullDebug(COMPONENT_NFS_V4)) {
407  				char str[LOG_BUFF_LEN] = "\0";
408  				struct display_buffer dspbuf = {sizeof(str), str, str};
409  	
410  				display_stateid(&dspbuf, found_state);
411  	
412  				LogFullDebug(COMPONENT_NFS_V4,
413  					     "found matching %s", str);
414  			}
415  			dec_state_t_ref(found_state);
416  		}
417  	
418  		LogFullDebug(COMPONENT_NFS_V4, "done with CLAIM_DELEGATE_CUR");
419  	
420  		return NFS4_OK;
421  	}
422  	
423  	/**
424  	 * @brief Create a new delegation state then get the delegation.
425  	 *
426  	 * Create a new delegation state for this client and file.
427  	 * Then attempt to get a LEASE lock to delegate the file
428  	 * according to whether the client opened READ or READ/WRITE.
429  	 *
430  	 * @note state_lock must be held for WRITE
431  	 *
432  	 * @param[in] data Compound data for this request
433  	 * @param[in] op NFS arguments for the request
434  	 * @param[in] open_state Open state for the inode to be delegated.
435  	 * @param[in] openowner Open owner of the open state.
436  	 * @param[in] client Client that will own the delegation.
437  	 * @param[in/out] resok Delegation attempt result to be returned to client.
438  	 * @param[in] prerecall flag for reclaims.
439  	 */
440  	static void get_delegation(compound_data_t *data, OPEN4args *args,
441  				   state_t *open_state, state_owner_t *openowner,
442  				   nfs_client_id_t *client, OPEN4resok *resok,
443  				   bool prerecall)
444  	{
445  		state_status_t state_status;
446  		union state_data state_data;
447  		open_delegation_type4 deleg_type;
448  		state_owner_t *clientowner = &client->cid_owner;
449  		struct state_refer refer;
450  		state_t *new_state = NULL;
451  		struct state_hdl *ostate;
452  		open_write_delegation4 *writeres =
453  			&resok->delegation.open_delegation4_u.write;
454  		open_read_delegation4 *readres =
455  			&resok->delegation.open_delegation4_u.read;
456  		open_none_delegation4 *whynone =
457  			&resok->delegation.open_delegation4_u.od_whynone;
458  	
459  		ostate = data->current_obj->state_hdl;
460  		if (!ostate) {
461  			LogFullDebug(COMPONENT_NFS_V4_LOCK, "Could not get file state");
462  			whynone->ond_why = WND4_RESOURCE;
463  			return;
464  		}
465  	
466  		/* Record the sequence info */
467  		if (data->minorversion > 0) {
468  			memcpy(refer.session,
469  			       data->session->session_id,
470  			       sizeof(sessionid4));
471  			refer.sequence = data->sequence;
472  			refer.slot = data->slotid;
473  		}
474  	
475  		if (args->share_access & OPEN4_SHARE_ACCESS_WRITE) {
476  			deleg_type = OPEN_DELEGATE_WRITE;
477  		} else {
478  			assert(args->share_access & OPEN4_SHARE_ACCESS_READ);
479  			deleg_type = OPEN_DELEGATE_READ;
480  		}
481  	
482  		LogDebug(COMPONENT_STATE, "Attempting to grant %s delegation",
483  			 deleg_type == OPEN_DELEGATE_WRITE ? "WRITE" : "READ");
484  	
485  		init_new_deleg_state(&state_data, deleg_type, client);
486  	
487  		/* Add the delegation state */
488  		state_status = state_add_impl(data->current_obj, STATE_TYPE_DELEG,
489  					      &state_data,
490  					      clientowner, &new_state,
491  					      data->minorversion > 0 ? &refer : NULL);
492  		if (state_status != STATE_SUCCESS) {
493  			LogDebug(COMPONENT_NFS_V4_LOCK,
494  				 "get delegation call failed to add state with status %s",
495  				 state_err_str(state_status));
496  			whynone->ond_why = WND4_RESOURCE;
497  			return;
498  		}
499  		new_state->state_seqid++;
500  	
501  		LogFullDebugOpaque(COMPONENT_STATE,
502  				   "delegation state added, stateid: %s",
503  				   100, new_state->stateid_other, OTHERSIZE);
504  	
505  		/* acquire_lease_lock() gets the delegation from FSAL */
506  		state_status = acquire_lease_lock(ostate, clientowner, new_state);
507  		if (state_status != STATE_SUCCESS) {
508  			if (args->claim.claim != CLAIM_PREVIOUS) {
509  				LogDebug(COMPONENT_NFS_V4_LOCK,
510  					 "get delegation call added state but failed to lock with status %s",
511  					 state_err_str(state_status));
512  				state_del_locked(new_state);
513  				dec_state_t_ref(new_state);
514  				if (state_status == STATE_LOCK_CONFLICT)
515  					whynone->ond_why = WND4_CONTENTION;
516  				else
517  					whynone->ond_why = WND4_RESOURCE;
518  				return;
519  			}
520  			prerecall = true;
521  		}
522  	
523  		resok->delegation.delegation_type = deleg_type;
524  		ostate->file.fdeleg_stats.fds_deleg_type = deleg_type;
525  		if (deleg_type == OPEN_DELEGATE_WRITE) {
526  			nfs_space_limit4 *space_limit = &writeres->space_limit;
527  	
528  			space_limit->limitby = NFS_LIMIT_SIZE;
529  			space_limit->nfs_space_limit4_u.filesize =
530  					DELEG_SPACE_LIMIT_FILESZ;
531  			COPY_STATEID(&writeres->stateid, new_state);
532  			writeres->recall = prerecall;
533  			get_deleg_perm(&writeres->permissions, deleg_type);
534  		} else {
535  			assert(deleg_type == OPEN_DELEGATE_READ);
536  			COPY_STATEID(&readres->stateid, new_state);
537  			readres->recall = prerecall;
538  			get_deleg_perm(&readres->permissions, deleg_type);
539  		}
540  	
541  		new_state->state_data.deleg.share_access =
542  			args->share_access & OPEN4_SHARE_ACCESS_BOTH;
543  		new_state->state_data.deleg.share_deny =
544  			args->share_deny;
545  	
546  		if (isDebug(COMPONENT_NFS_V4_LOCK)) {
547  			char str1[LOG_BUFF_LEN / 2] = "\0";
548  			char str2[LOG_BUFF_LEN / 2] = "\0";
549  			struct display_buffer dspbuf1 = {sizeof(str1), str1, str1};
550  			struct display_buffer dspbuf2 = {sizeof(str2), str2, str2};
551  	
552  			display_nfs4_owner(&dspbuf1, openowner);
553  			display_nfs4_owner(&dspbuf2, clientowner);
554  	
555  			LogDebug(COMPONENT_NFS_V4_LOCK,
556  				 "get delegation openowner %s clientowner %s status %s",
557  				 str1, str2, state_err_str(state_status));
558  		}
559  	
560  		dec_state_t_ref(new_state);
561  	}
562  	
563  	static void do_delegation(OPEN4args *arg_OPEN4, OPEN4res *res_OPEN4,
564  				  compound_data_t *data, state_owner_t *owner,
565  				  state_t *open_state, nfs_client_id_t *clientid)
566  	{
567  		OPEN4resok *resok = &res_OPEN4->OPEN4res_u.resok4;
568  		bool prerecall;
569  		struct state_hdl *ostate;
570  	
571  		ostate = data->current_obj->state_hdl;
572  		if (!ostate) {
573  			LogFullDebug(COMPONENT_STATE, "Could not get file state");
574  			return;
575  		}
576  	
577  		/* This will be updated later if we actually delegate */
578  		if (clientid->cid_minorversion == 0)
579  			resok->delegation.delegation_type = OPEN_DELEGATE_NONE;
580  		else
581  			resok->delegation.delegation_type = OPEN_DELEGATE_NONE_EXT;
582  	
583  		/* Client doesn't want a delegation. */
584  		if (arg_OPEN4->share_access & OPEN4_SHARE_ACCESS_WANT_NO_DELEG) {
585  			resok->delegation.open_delegation4_u.od_whynone.ond_why =
586  									WND4_NOT_WANTED;
587  			LogFullDebug(COMPONENT_STATE, "Client didn't want delegation.");
588  			return;
589  		}
590  	
591  		/* Check if delegations are supported */
592  		if (!deleg_supported(data->current_obj, op_ctx->fsal_export,
593  				     op_ctx->export_perms, arg_OPEN4->share_access)) {
594  			resok->delegation.open_delegation4_u.od_whynone.ond_why =
595  								WND4_NOT_SUPP_FTYPE;
596  			LogFullDebug(COMPONENT_STATE, "Delegation type not supported.");
597  			return;
598  		}
599  	
600  		/* Decide if we should delegate, then add it. */
601  		if (can_we_grant_deleg(ostate, open_state) &&
602  		    should_we_grant_deleg(ostate, clientid, open_state,
603  					  arg_OPEN4, resok, owner, &prerecall)) {
604  			/* Update delegation open stats */
605  			if (ostate->file.fdeleg_stats.fds_num_opens == 0)
606  				ostate->file.fdeleg_stats.fds_first_open = time(NULL);
607  			ostate->file.fdeleg_stats.fds_num_opens++;
608  	
609  			LogDebug(COMPONENT_STATE, "Attempting to grant delegation");
610  			get_delegation(data, arg_OPEN4, open_state, owner, clientid,
611  				       resok, prerecall);
612  		}
613  	}
614  	
615  	/**
616  	 * @brief NFS4_OP_OPEN create processing for use with extended FSAL API
617  	 *
618  	 * @param[in]     arg         Arguments for nfs4_op
619  	 * @param[in,out] data        Compound request's data
620  	 * @param[out]    res_OPEN4   Results for nfs4_op
621  	 * @param[in,out] verifier    The verifier for exclusive create
622  	 * @param[in,out] createmode  The method of create
623  	 * @param[in,out] sattr       The attributes to set
624  	 *
625  	 */
626  	
627  	static void open4_ex_create_args(OPEN4args *arg,
628  					 compound_data_t *data,
629  					 OPEN4res *res_OPEN4,
630  					 void *verifier,
631  					 enum fsal_create_mode *createmode,
632  					 struct attrlist *sattr)
633  	{
634  		createhow4 *createhow = &arg->openhow.openflag4_u.how;
635  		fattr4 *arg_attrs = NULL;
636  	
637  		*createmode = nfs4_createmode_to_fsal(createhow->mode);
638  	
639  		if (createhow->mode == EXCLUSIVE4_1) {
640  			memcpy(verifier,
641  			       createhow->createhow4_u.ch_createboth.cva_verf,
642  			       sizeof(fsal_verifier_t));
643  		} else if (createhow->mode == EXCLUSIVE4) {
644  			memcpy(verifier,
645  			       createhow->createhow4_u.createverf,
646  			       sizeof(fsal_verifier_t));
647  		}
648  	
649  		/* Select the correct attributes */
650  		if (createhow->mode == GUARDED4 || createhow->mode == UNCHECKED4)
651  			arg_attrs = &createhow->createhow4_u.createattrs;
652  		else if (createhow->mode == EXCLUSIVE4_1)
653  			arg_attrs = &createhow->createhow4_u.ch_createboth.cva_attrs;
654  	
655  		if (arg_attrs != NULL) {
656  			/* Check if asked attributes are correct */
657  			if (!nfs4_Fattr_Supported(arg_attrs)) {
658  				res_OPEN4->status = NFS4ERR_ATTRNOTSUPP;
659  				return;
660  			}
661  	
662  			if (!nfs4_Fattr_Check_Access(arg_attrs, FATTR4_ATTR_WRITE)) {
663  				res_OPEN4->status = NFS4ERR_INVAL;
664  				return;
665  			}
666  	
667  			/* Convert the attributes */
668  			if (arg_attrs->attrmask.bitmap4_len != 0) {
669  				/* Convert fattr4 so nfs4_sattr */
670  				res_OPEN4->status =
671  				    nfs4_Fattr_To_FSAL_attr(sattr, arg_attrs, data);
672  	
673  				if (res_OPEN4->status != NFS4_OK)
674  					return;
675  			}
676  	
677  			if (createhow->mode == EXCLUSIVE4_1) {
678  				/** @todo FSF: this needs to be corrected in case FSAL
679  				 *             uses different attributes for the
680  				 *             verifier.
681  				 */
682  				/* Check that we aren't trying to set the verifier
683  				 * attributes.
684  				 */
685  				if (FSAL_TEST_MASK(sattr->valid_mask, ATTR_ATIME) ||
686  				    FSAL_TEST_MASK(sattr->valid_mask, ATTR_MTIME)) {
687  					res_OPEN4->status = NFS4ERR_INVAL;
688  					return;
689  				}
690  			}
691  	
692  			/* If owner or owner_group are set, and the credential was
693  			 * squashed, then we must squash the set owner and owner_group.
694  			 */
695  			squash_setattr(sattr);
696  		}
697  	
698  		if (!(sattr->valid_mask & ATTR_MODE)) {
699  			/* Make sure mode is set, even for exclusive create. */
700  			sattr->mode = 0600;
701  			sattr->valid_mask |= ATTR_MODE;
702  		}
703  	}
704  	
705  	/**
706  	 * @brief NFS4_OP_OPEN processing using extended FSAL API
707  	 *
708  	 * This function impelments the NFS4_OP_OPEN operation, which
709  	 * potentially creates and opens a regular file.
710  	 *
711  	 * @param[in]     arg         Arguments for nfs4_op
712  	 * @param[in,out] data        Compound request's data
713  	 * @param[out]    res_OPEN4   Results for nfs4_op
714  	 * @param[out]    file_state  state_t created for this operation
715  	 * @param[out]    new_state   Indicates if the state_t is new
716  	 *
717  	 */
718  	
719  	static void open4_ex(OPEN4args *arg,
720  			     compound_data_t *data,
721  			     OPEN4res *res_OPEN4,
722  			     nfs_client_id_t *clientid,
723  			     state_owner_t *owner,
724  			     state_t **file_state,
725  			     bool *new_state)
726  	{
727  		/* Parent directory in which to open the file. */
728  		struct fsal_obj_handle *parent = NULL;
729  		/* The entry we associated with the desired file before open. */
730  		struct fsal_obj_handle *file_obj = NULL;
731  		/* Indicator that file_obj came from lookup. */
732  		bool looked_up_file_obj = false;
733  		/* The in_obj to pass to fsal_open2. */
(1) Event assign_zero: Assigning: "in_obj" = "NULL".
Also see events: [var_deref_model]
734  		struct fsal_obj_handle *in_obj = NULL;
735  		/* The entry open associated with the file. */
736  		struct fsal_obj_handle *out_obj = NULL;
737  		fsal_openflags_t openflags = 0;
738  		fsal_openflags_t old_openflags = 0;
739  		enum fsal_create_mode createmode = FSAL_NO_CREATE;
740  		/* The filename to create */
741  		char *filename = NULL;
742  		/* The supplied calim type */
743  		open_claim_type4 claim = arg->claim.claim;
744  		fsal_verifier_t verifier;
745  		struct attrlist sattr;
746  		/* Status for fsal calls */
747  		fsal_status_t status = {0, 0};
748  		/* The open state for the file */
749  		bool state_lock_held = false;
750  	
751  		/* Make sure the attributes are initialized */
752  		memset(&sattr, 0, sizeof(sattr));
753  	
754  		/* Make sure... */
755  		*file_state = NULL;
756  		*new_state = false;
757  	
758  		/* Pre-process the claim type */
(2) Event switch: Switch case value "CLAIM_PREVIOUS".
759  		switch (claim) {
760  		case CLAIM_NULL:
761  			/* Check parent */
762  			parent = data->current_obj;
763  			in_obj = parent;
764  	
765  			/* Parent must be a directory */
766  			if (parent->type != DIRECTORY) {
767  				if (parent->type == SYMBOLIC_LINK) {
768  					res_OPEN4->status = NFS4ERR_SYMLINK;
769  					goto out;
770  				} else {
771  					res_OPEN4->status = NFS4ERR_NOTDIR;
772  					goto out;
773  				}
774  			}
775  	
776  			/* Validate and convert the utf8 filename */
777  			res_OPEN4->status =
778  			    nfs4_utf8string2dynamic(&arg->claim.open_claim4_u.file,
779  						    UTF8_SCAN_ALL, &filename);
780  	
781  			if (res_OPEN4->status != NFS4_OK)
782  				goto out;
783  	
784  			/* Set the createmode if appropriate) */
785  			if (arg->openhow.opentype == OPEN4_CREATE) {
786  				open4_ex_create_args(arg, data, res_OPEN4, verifier,
787  						     &createmode, &sattr);
788  	
789  				if (res_OPEN4->status != NFS4_OK)
790  					goto out;
791  			}
792  	
793  			status = fsal_lookup(parent, filename, &file_obj, NULL);
794  	
795  			if (!FSAL_IS_ERROR(status)) {
796  				/* Check create situations. */
797  				if (arg->openhow.opentype == OPEN4_CREATE) {
798  					if (createmode >= FSAL_EXCLUSIVE) {
799  						/* Could be a replay, need to continue.
800  						 */
801  						LogFullDebug(COMPONENT_STATE,
802  							     "EXCLUSIVE open with existing file %s",
803  							     filename);
804  					} else if (createmode == FSAL_GUARDED) {
805  						/* This will be a failure no matter'
806  						 * what.
807  						 */
808  						looked_up_file_obj = true;
809  						res_OPEN4->status = NFS4ERR_EXIST;
810  						goto out;
811  					} else {
812  						/* FSAL_UNCHECKED, may be a truncate
813  						 * and we need to pass in the case
814  						 * of fsal_reopen2 case.
815  						 */
816  						if (FSAL_TEST_MASK(sattr.valid_mask,
817  								   ATTR_SIZE) &&
818  						    sattr.filesize == 0) {
819  							LogFullDebug(COMPONENT_STATE,
820  								     "Truncate");
821  							openflags |= FSAL_O_TRUNC;
822  						}
823  					}
824  				}
825  	
826  				/* We found the file by lookup, discard the filename
827  				 * and remember that we found the entry by lookup.
828  				 */
829  				looked_up_file_obj = true;
830  				gsh_free(filename);
831  				filename = NULL;
832  			} else if (status.major != ERR_FSAL_NOENT ||
833  				   arg->openhow.opentype != OPEN4_CREATE) {
834  				/* A real error occurred */
835  				res_OPEN4->status = nfs4_Errno_status(status);
836  				goto out;
837  			}
838  	
839  			break;
840  	
841  			/* Both of these just use the current filehandle. */
(3) Event switch_case: Reached case "CLAIM_PREVIOUS".
842  		case CLAIM_PREVIOUS:
843  			owner->so_owner.so_nfs4_owner.so_confirmed = true;
(4) Event cond_false: Condition "!nfs4_check_deleg_reclaim(clientid, &data->currentFH)", taking false branch.
844  			if (!nfs4_check_deleg_reclaim(clientid, &data->currentFH)) {
845  				/* It must have been revoked. Can't reclaim.*/
846  				LogInfo(COMPONENT_NFS_V4, "Can't reclaim delegation");
847  				res_OPEN4->status = NFS4ERR_RECLAIM_BAD;
848  				goto out;
(5) Event if_end: End of if statement.
849  			}
850  			file_obj = data->current_obj;
(6) Event break: Breaking from switch.
851  			break;
852  	
853  		case CLAIM_FH:
854  			file_obj = data->current_obj;
855  			break;
856  	
857  		case CLAIM_DELEGATE_PREV:
858  			/* FIXME: Remove this when we have full support
859  			 * for CLAIM_DELEGATE_PREV and delegpurge operations
860  			 */
861  			res_OPEN4->status = NFS4ERR_NOTSUPP;
862  			goto out;
863  	
864  		case CLAIM_DELEGATE_CUR:
865  		case CLAIM_DELEG_CUR_FH:
866  			res_OPEN4->status = open4_claim_deleg(arg, data);
867  			if (res_OPEN4->status != NFS4_OK)
868  				goto out;
869  			file_obj = data->current_obj;
870  			break;
871  	
872  		default:
873  			LogFatal(COMPONENT_STATE,
874  				 "Programming error.  Invalid claim after check.");
(7) Event switch_end: Reached end of switch.
875  		}
876  	
(8) Event cond_true: Condition "(arg->share_access & 1) != 0", taking true branch.
877  		if ((arg->share_access & OPEN4_SHARE_ACCESS_READ) != 0)
878  			openflags |= FSAL_O_READ;
879  	
(9) Event cond_true: Condition "(arg->share_access & 2) != 0", taking true branch.
880  		if ((arg->share_access & OPEN4_SHARE_ACCESS_WRITE) != 0)
881  			openflags |= FSAL_O_WRITE;
882  	
(10) Event cond_true: Condition "(arg->share_deny & 1) != 0", taking true branch.
883  		if ((arg->share_deny & OPEN4_SHARE_DENY_READ) != 0)
884  			openflags |= FSAL_O_DENY_READ;
885  	
(11) Event cond_true: Condition "(arg->share_deny & 2) != 0", taking true branch.
886  		if ((arg->share_deny & OPEN4_SHARE_DENY_WRITE) != 0)
887  			openflags |= FSAL_O_DENY_WRITE_MAND;
888  	
889  		/* Check if file_obj a REGULAR_FILE */
(12) Event cond_false: Condition "file_obj != NULL", taking false branch.
890  		if (file_obj != NULL && file_obj->type != REGULAR_FILE) {
891  			LogDebug(COMPONENT_NFS_V4,
892  				 "Wrong file type expected REGULAR_FILE actual %s",
893  				 object_file_type_to_str(file_obj->type));
894  	
895  			if (file_obj->type == DIRECTORY) {
896  				res_OPEN4->status = NFS4ERR_ISDIR;
897  			} else {
898  				/* All special nodes must return NFS4ERR_SYMLINK for
899  				 * proper client behavior per this linux-nfs post:
900  				 * http://marc.info/?l=linux-nfs&m=131342421825436&w=2
901  				 */
902  				res_OPEN4->status = NFS4ERR_SYMLINK;
903  			}
904  	
905  			goto out;
(13) Event if_end: End of if statement.
906  		}
907  	
(14) Event cond_false: Condition "file_obj != NULL", taking false branch.
908  		if (file_obj != NULL) {
909  			/* Go ahead and take the state lock now. */
910  			PTHREAD_RWLOCK_wrlock(&file_obj->state_hdl->state_lock);
911  			state_lock_held = true;
912  			in_obj = file_obj;
913  	
914  			/* Check if any existing delegations conflict with this open.
915  			 * Delegation recalls will be scheduled if there is a conflict.
916  			 */
917  			if (arg->claim.claim != CLAIM_DELEGATE_CUR &&
918  			    arg->claim.claim != CLAIM_DELEG_CUR_FH &&
919  			    state_deleg_conflict_impl(file_obj,
920  						     (arg->share_access &
921  						      OPEN4_SHARE_ACCESS_WRITE) != 0)) {
922  				res_OPEN4->status = NFS4ERR_DELAY;
923  				goto out;
924  			}
925  	
926  			/* Check if there is already a state for this entry and owner.
927  			 */
928  			*file_state = nfs4_State_Get_Obj(file_obj, owner);
929  	
930  			if (isFullDebug(COMPONENT_STATE) && *file_state != NULL) {
931  				char str[LOG_BUFF_LEN] = "\0";
932  				struct display_buffer dspbuf = {sizeof(str), str, str};
933  	
934  				display_stateid(&dspbuf, *file_state);
935  	
936  				LogFullDebug(COMPONENT_STATE,
937  					     "Found existing state %s",
938  					     str);
939  			}
940  	
941  			/* Check if open from another export */
942  			if (*file_state != NULL &&
943  			    !state_same_export(*file_state, op_ctx->ctx_export)) {
944  				LogEvent(COMPONENT_STATE,
945  					 "Lock Owner Export Conflict, Lock held for export %"
946  					 PRIu16" request for export %"PRIu16,
947  					 state_export_id(*file_state),
948  					 op_ctx->ctx_export->export_id);
949  				res_OPEN4->status = NFS4ERR_INVAL;
950  				goto out;
951  			}
(15) Event if_end: End of if statement.
952  		}
953  	
954  		/* If that did not succeed, allocate a state from the FSAL. */
(16) Event cond_true: Condition "*file_state == NULL", taking true branch.
955  		if (*file_state == NULL) {
956  			*file_state = op_ctx->fsal_export->exp_ops.alloc_state(
957  								op_ctx->fsal_export,
958  								STATE_TYPE_SHARE,
959  								NULL);
960  	
961  			/* Remember we allocated a new state */
962  			*new_state = true;
963  	
964  			/* We are ready to perform the open (with possible create).
965  			 * in_obj has been set to the file itself or the parent.
966  			 * filename is NULL if in_obj is the file itself.
967  			 *
968  			 * Permission check has been done on directory if appropriate,
969  			 * otherwise fsal_open2 will do a directory permission
970  			 * check.
971  			 *
972  			 * fsal_open2 handles the permission check on the file
973  			 * itself and also handles all the share reservation stuff.
974  			 *
975  			 * fsal_open2 returns with a ref on out_obj, which should be
976  			 * passed to the state.
977  			 */
(17) Event cond_true: Condition "!!(component_log_level[COMPONENT_STATE] >= NIV_FULL_DEBUG)", taking true branch.
(18) Event cond_true: Condition "!!(component_log_level[COMPONENT_STATE] >= NIV_FULL_DEBUG)", taking true branch.
978  			LogFullDebug(COMPONENT_STATE,
979  				     "Calling open2 for %s", filename);
980  	
(19) Event var_deref_model: Passing null pointer "in_obj" to "fsal_open2", which dereferences it. [details]
Also see events: [assign_zero]
981  			status = fsal_open2(in_obj,
982  					    *file_state,
983  					    openflags,
984  					    createmode,
985  					    filename,
986  					    &sattr,
987  					    verifier,
988  					    &out_obj,
989  					    NULL);
990  	
991  			if (FSAL_IS_ERROR(status)) {
992  				res_OPEN4->status = nfs4_Errno_status(status);
993  				goto out;
994  			}
995  		} else if (createmode >= FSAL_EXCLUSIVE) {
996  			/* We have an EXCLUSIVE create with an existing
997  			 * state. We still need to verify it, but no need
998  			 * to call reopen2.
999  			 */
1000 			LogFullDebug(COMPONENT_STATE, "Calling verify2 ");
1001 	
1002 			status = fsal_verify2(file_obj, verifier);
1003 	
1004 			if (FSAL_IS_ERROR(status)) {
1005 				res_OPEN4->status = nfs4_Errno_status(status);
1006 				goto out;
1007 			}
1008 	
1009 			/* We need an extra reference below. */
1010 			file_obj->obj_ops->get_ref(file_obj);
1011 		} else {
1012 			old_openflags =
1013 				file_obj->obj_ops->status2(file_obj, *file_state);
1014 	
1015 			/* Open upgrade */
1016 			LogFullDebug(COMPONENT_STATE, "Calling reopen2");
1017 	
1018 			status = fsal_reopen2(file_obj, *file_state,
1019 					      openflags | old_openflags,
1020 					      false);
1021 	
1022 			if (FSAL_IS_ERROR(status)) {
1023 				res_OPEN4->status = nfs4_Errno_status(status);
1024 				goto out;
1025 			}
1026 	
1027 			/* We need an extra reference below. */
1028 			file_obj->obj_ops->get_ref(file_obj);
1029 		}
1030 	
1031 		if (file_obj == NULL) {
1032 			/* We have a new cache inode entry, take the state lock. */
1033 			file_obj = out_obj;
1034 			PTHREAD_RWLOCK_wrlock(&file_obj->state_hdl->state_lock);
1035 			state_lock_held = true;
1036 		}
1037 	
1038 		/* Now the state_lock is held for sure and we have an extra LRU
1039 		 * reference to file_obj, which is the opened file.
1040 		 */
1041 	
1042 		if (*new_state) {
1043 			/* The state data to be added */
1044 			union state_data candidate_data;
1045 			/* Tracking data for the open state */
1046 			struct state_refer refer, *p_refer = NULL;
1047 			state_status_t state_status;
1048 	
1049 			candidate_data.share.share_access =
1050 			    arg->share_access & OPEN4_SHARE_ACCESS_BOTH;
1051 			candidate_data.share.share_deny = arg->share_deny;
1052 			candidate_data.share.share_access_prev =
1053 				(1 << candidate_data.share.share_access);
1054 			candidate_data.share.share_deny_prev =
1055 				(1 << candidate_data.share.share_deny);
1056 	
1057 			LogFullDebug(COMPONENT_STATE,
1058 				     "Creating new state access=%x deny=%x access_prev=%x deny_prev=%x",
1059 				     candidate_data.share.share_access,
1060 				     candidate_data.share.share_deny,
1061 				     candidate_data.share.share_access_prev,
1062 				     candidate_data.share.share_deny_prev);
1063 	
1064 			/* Record the sequence info */
1065 			if (data->minorversion > 0) {
1066 				memcpy(refer.session,
1067 				       data->session->session_id,
1068 				       sizeof(sessionid4));
1069 				refer.sequence = data->sequence;
1070 				refer.slot = data->slotid;
1071 				p_refer = &refer;
1072 			}
1073 	
1074 			/* We need to register this state now. */
1075 			state_status = state_add_impl(file_obj,
1076 						      STATE_TYPE_SHARE,
1077 						      &candidate_data,
1078 						      owner,
1079 						      file_state,
1080 						      p_refer);
1081 	
1082 			if (state_status != STATE_SUCCESS) {
1083 				/* state_add_impl failure closed and freed state.
1084 				 * file_state will also be NULL at this point. Also
1085 				 * release the ref on file_obj, since the state add
1086 				 * failed.
1087 				 */
1088 				file_obj->obj_ops->put_ref(file_obj);
1089 				res_OPEN4->status = nfs4_Errno_state(state_status);
1090 				*new_state = false;
1091 				goto out;
1092 			}
1093 	
1094 			glist_init(&(*file_state)->state_data.share.share_lockstates);
1095 		}
1096 	
1097 		res_OPEN4->status = open4_create_fh(data, file_obj, true);
1098 	
1099 		if (res_OPEN4->status != NFS4_OK) {
1100 			if (*new_state) {
1101 				/* state_del_locked will close the file. */
1102 				state_del_locked(*file_state);
1103 				*file_state = NULL;
1104 				*new_state = false;
1105 			} else {
1106 				/*Do an open downgrade to the old open flags */
1107 				status = file_obj->obj_ops->reopen2(file_obj,
1108 								   *file_state,
1109 								   old_openflags);
1110 				if (FSAL_IS_ERROR(status)) {
1111 					LogCrit(COMPONENT_NFS_V4,
1112 						"Failed to allocate handle, reopen2 failed with %s",
1113 						fsal_err_txt(status));
1114 				}
1115 	
1116 				/* Need to release the state_lock before the put_ref
1117 				 * call.
1118 				 */
1119 				PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock);
1120 				state_lock_held = false;
1121 	
1122 				/* Release the extra LRU reference on file_obj. */
1123 				file_obj->obj_ops->put_ref(file_obj);
1124 				goto out;
1125 			}
1126 		}
1127 	
1128 		/* Since open4_create_fh succeeded the LRU reference to file_obj was
1129 		 * consumed by data->current_obj.
1130 		 */
1131 	
1132 		if (!(*new_state)) {
1133 			LogFullDebug(COMPONENT_STATE,
1134 				     "Open upgrade old access=%x deny=%x access_prev=%x deny_prev=%x",
1135 				     (*file_state)->state_data.share.share_access,
1136 				     (*file_state)->state_data.share.share_deny,
1137 				     (*file_state)->state_data.share.share_access_prev,
1138 				     (*file_state)->state_data.share.share_deny_prev);
1139 	
1140 			LogFullDebug(COMPONENT_STATE,
1141 				     "Open upgrade to access=%x deny=%x",
1142 				     arg->share_access,
1143 				     arg->share_deny);
1144 	
1145 			/* Update share_access and share_deny */
1146 			(*file_state)->state_data.share.share_access |=
1147 				arg->share_access & OPEN4_SHARE_ACCESS_BOTH;
1148 	
1149 			(*file_state)->state_data.share.share_deny |=
1150 				arg->share_deny;
1151 	
1152 			/* Update share_access_prev and share_deny_prev */
1153 			(*file_state)->state_data.share.share_access_prev |=
1154 				(1 << (arg->share_access & OPEN4_SHARE_ACCESS_BOTH));
1155 	
1156 			(*file_state)->state_data.share.share_deny_prev |=
1157 				(1 << arg->share_deny);
1158 	
1159 			LogFullDebug(COMPONENT_STATE,
1160 				     "Open upgrade new access=%x deny=%x access_prev=%x deny_prev=%x",
1161 				     (*file_state)->state_data.share.share_access,
1162 				     (*file_state)->state_data.share.share_deny,
1163 				     (*file_state)->state_data.share.share_access_prev,
1164 				     (*file_state)->state_data.share.share_deny_prev);
1165 		}
1166 	
1167 		do_delegation(arg, res_OPEN4, data, owner, *file_state, clientid);
1168 	 out:
1169 	
1170 		/* Release the attributes (may release an inherited ACL) */
1171 		fsal_release_attrs(&sattr);
1172 	
1173 		if (state_lock_held)
1174 			PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock);
1175 	
1176 		if (filename)
1177 			gsh_free(filename);
1178 	
1179 		if (res_OPEN4->status != NFS4_OK) {
1180 			/* Cleanup state on error */
1181 			if (*new_state)
1182 				(*file_state)
1183 					->state_exp->exp_ops.free_state(
1184 						(*file_state)->state_exp, *file_state);
1185 			else if (*file_state != NULL)
1186 				dec_state_t_ref(*file_state);
1187 			*file_state = NULL;
1188 		}
1189 	
1190 		if (looked_up_file_obj) {
1191 			/* We got file_obj via lookup, we need to unref it. */
1192 			file_obj->obj_ops->put_ref(file_obj);
1193 		}
1194 	}
1195 	
1196 	/**
1197 	 * @brief NFS4_OP_OPEN
1198 	 *
1199 	 * This function impelments the NFS4_OP_OPEN operation, which
1200 	 * potentially creates and opens a regular file.
1201 	 *
1202 	 * @param[in]     op   Arguments for nfs4_op
1203 	 * @param[in,out] data Compound request's data
1204 	 * @param[out]    resp Results for nfs4_op
1205 	 *
1206 	 * @return per RFC5661, pp. 369-70
1207 	 */
1208 	
1209 	enum nfs_req_result nfs4_op_open(struct nfs_argop4 *op, compound_data_t *data,
1210 					 struct nfs_resop4 *resp)
1211 	{
1212 		/* Shorter alias for OPEN4 arguments */
1213 		OPEN4args * const arg_OPEN4 = &(op->nfs_argop4_u.opopen);
1214 		/* Shorter alias for OPEN4 response */
1215 		OPEN4res * const res_OPEN4 = &(resp->nfs_resop4_u.opopen);
1216 		/* The handle from which the change_info4 is to be
1217 		 * generated.  Every mention of change_info4 in RFC5661
1218 		 * speaks of the parent directory of the file being opened.
1219 		 * However, with CLAIM_FH, CLAIM_DELEG_CUR_FH, and
1220 		 * CLAIM_DELEG_PREV_FH, there is no way to derive the parent
1221 		 * directory from the file handle.  It is Unclear what the
1222 		 * correct behavior is.  In our implementation, we take the
1223 		 * change_info4 of whatever filehandle is current when the
1224 		 * OPEN operation is invoked.
1225 		 */
1226 		struct fsal_obj_handle *obj_change = NULL;
1227 		/* The found client record */
1228 		nfs_client_id_t *clientid = NULL;
1229 		/* The found or created state owner for this open */
1230 		state_owner_t *owner = NULL;
1231 		/* The supplied calim type */
1232 		open_claim_type4 claim = arg_OPEN4->claim.claim;
1233 		/* The open state for the file */
1234 		state_t *file_state = NULL;
1235 		/* True if the state was newly created */
1236 		bool new_state = false;
1237 		/* True if a grace reference was taken */
1238 		bool grace_ref = false;
1239 		int retval;
1240 	
1241 		LogDebug(COMPONENT_STATE,
1242 			 "Entering NFS v4 OPEN handler -----------------------------");
1243 	
1244 		/* What kind of open is it ? */
1245 		LogFullDebug(COMPONENT_STATE,
1246 			     "OPEN: Claim type = %d, Open Type = %d, Share Deny = %d, Share Access = %d ",
1247 			     arg_OPEN4->claim.claim,
1248 			     arg_OPEN4->openhow.opentype,
1249 			     arg_OPEN4->share_deny,
1250 			     arg_OPEN4->share_access);
1251 	
1252 		resp->resop = NFS4_OP_OPEN;
1253 		res_OPEN4->status = NFS4_OK;
1254 		res_OPEN4->OPEN4res_u.resok4.rflags = 0;
1255 	
1256 		/* Check export permissions if OPEN4_CREATE */
1257 		if ((arg_OPEN4->openhow.opentype == OPEN4_CREATE) &&
1258 		    ((op_ctx->export_perms->options &
1259 		      EXPORT_OPTION_MD_WRITE_ACCESS) == 0)) {
1260 			res_OPEN4->status = NFS4ERR_ROFS;
1261 	
1262 			LogDebug(COMPONENT_NFS_V4,
1263 				 "Status of OP_OPEN due to export permissions = %s",
1264 				 nfsstat4_to_str(res_OPEN4->status));
1265 			return NFS_REQ_ERROR;
1266 		}
1267 	
1268 		/* Check export permissions if OPEN4_SHARE_ACCESS_WRITE */
1269 		if (((arg_OPEN4->share_access & OPEN4_SHARE_ACCESS_WRITE) != 0) &&
1270 		    ((op_ctx->export_perms->options &
1271 		      EXPORT_OPTION_WRITE_ACCESS) == 0)) {
1272 			res_OPEN4->status = NFS4ERR_ROFS;
1273 	
1274 			LogDebug(COMPONENT_NFS_V4,
1275 				 "Status of OP_OPEN due to export permissions = %s",
1276 				 nfsstat4_to_str(res_OPEN4->status));
1277 	
1278 			return NFS_REQ_ERROR;
1279 		}
1280 	
1281 		/* Do basic checks on a filehandle */
1282 		res_OPEN4->status = nfs4_sanity_check_FH(data, NO_FILE_TYPE, false);
1283 	
1284 		if (res_OPEN4->status != NFS4_OK)
1285 			return NFS_REQ_ERROR;
1286 	
1287 		if (data->current_obj == NULL) {
1288 			/* This should be impossible, as PUTFH fills in the
1289 			 * current entry and previous checks weed out handles
1290 			 * in the PseudoFS and DS handles.
1291 			 */
1292 			res_OPEN4->status = NFS4ERR_SERVERFAULT;
1293 			LogCrit(COMPONENT_NFS_V4,
1294 				"Impossible condition in compound data at %s:%u.",
1295 				__FILE__, __LINE__);
1296 			return NFS_REQ_ERROR;
1297 		}
1298 	
1299 		/* It this a known client id? */
1300 		LogDebug(COMPONENT_STATE,
1301 			 "OPEN Client id = %" PRIx64,
1302 			 arg_OPEN4->owner.clientid);
1303 	
1304 		retval = nfs_client_id_get_confirmed(
1305 			data->minorversion == 0 ?
1306 				arg_OPEN4->owner.clientid :
1307 				data->session->clientid,
1308 			&clientid);
1309 	
1310 		if (retval != CLIENT_ID_SUCCESS) {
1311 			res_OPEN4->status = clientid_error_to_nfsstat(retval);
1312 			LogDebug(COMPONENT_NFS_V4,
1313 				 "nfs_client_id_get_confirmed failed");
1314 			return NFS_REQ_ERROR;
1315 		}
1316 	
1317 		/* Check if lease is expired and reserve it */
1318 		PTHREAD_MUTEX_lock(&clientid->cid_mutex);
1319 	
1320 		if (data->minorversion == 0 && !reserve_lease(clientid)) {
1321 			PTHREAD_MUTEX_unlock(&clientid->cid_mutex);
1322 			res_OPEN4->status = NFS4ERR_EXPIRED;
1323 			LogDebug(COMPONENT_NFS_V4, "Lease expired");
1324 			goto out3;
1325 		}
1326 	
1327 		PTHREAD_MUTEX_unlock(&clientid->cid_mutex);
1328 	
1329 		/* Get the open owner */
1330 		if (!open4_open_owner(op, data, resp, clientid, &owner)) {
1331 			LogDebug(COMPONENT_NFS_V4, "open4_open_owner failed");
1332 			goto out2;
1333 		}
1334 	
1335 		/* Do the claim check here, so we can save the result in the
1336 		 * owner for NFSv4.0.
1337 		 */
1338 		res_OPEN4->status = open4_validate_claim(data, claim, clientid,
1339 							 &grace_ref);
1340 		if (res_OPEN4->status != NFS4_OK) {
1341 			LogDebug(COMPONENT_NFS_V4, "open4_validate_claim failed");
1342 			goto out;
1343 		}
1344 	
1345 		/* After this point we know we have only CLAIM_NULL,
1346 		 * CLAIM_FH, or CLAIM_PREVIOUS, and that our grace period and
1347 		 * minor version are appropriate for the claim specified.
1348 		 */
1349 		if ((arg_OPEN4->openhow.opentype == OPEN4_CREATE)
1350 		    && (claim != CLAIM_NULL)) {
1351 			res_OPEN4->status = NFS4ERR_INVAL;
1352 			LogDebug(COMPONENT_NFS_V4, "OPEN4_CREATE but not CLAIM_NULL");
1353 			goto out2;
1354 		}
1355 	
1356 		/* So we still have a reference even after we repalce the
1357 		 * current FH.
1358 		 */
1359 		obj_change = data->current_obj;
1360 		obj_change->obj_ops->get_ref(obj_change);
1361 	
1362 		/* Update the change info for entry_change. */
1363 		res_OPEN4->OPEN4res_u.resok4.cinfo.before =
1364 			fsal_get_changeid4(obj_change);
1365 	
1366 		/* Check if share_access does not have any access set, or has
1367 		 * invalid bits that are set.  check that share_deny doesn't
1368 		 * have any invalid bits set.
1369 		 */
1370 		if (!(arg_OPEN4->share_access & OPEN4_SHARE_ACCESS_BOTH)
1371 		    || (data->minorversion == 0
1372 			&& arg_OPEN4->share_access & ~OPEN4_SHARE_ACCESS_BOTH)
1373 		    || (arg_OPEN4->share_access & (~OPEN4_SHARE_ACCESS_WANT_DELEG_MASK &
1374 						   ~OPEN4_SHARE_ACCESS_BOTH))
1375 		    || (arg_OPEN4->share_deny & ~OPEN4_SHARE_DENY_BOTH)) {
1376 			res_OPEN4->status = NFS4ERR_INVAL;
1377 			LogDebug(COMPONENT_NFS_V4,
1378 				 "Invalid SHARE_ACCESS or SHARE_DENY");
1379 			goto out;
1380 		}
1381 	
1382 		/* Utilize the extended FSAL APU functionality to perform the open. */
1383 		open4_ex(arg_OPEN4, data, res_OPEN4, clientid,
1384 			 owner, &file_state, &new_state);
1385 	
1386 		if (res_OPEN4->status != NFS4_OK)
1387 			goto out;
1388 	
1389 		memset(&res_OPEN4->OPEN4res_u.resok4.attrset,
1390 		       0,
1391 		       sizeof(struct bitmap4));
1392 	
1393 		if (arg_OPEN4->openhow.openflag4_u.how.mode == EXCLUSIVE4 ||
1394 		    arg_OPEN4->openhow.openflag4_u.how.mode == EXCLUSIVE4_1) {
1395 			struct bitmap4 *bits = &res_OPEN4->OPEN4res_u.resok4.attrset;
1396 	
1397 			set_attribute_in_bitmap(bits, FATTR4_TIME_ACCESS);
1398 			set_attribute_in_bitmap(bits, FATTR4_TIME_MODIFY);
1399 		}
1400 	
1401 		/* If server use OPEN_CONFIRM4, set the correct flag,
1402 		 * but not for 4.1 */
1403 		if (owner->so_owner.so_nfs4_owner.so_confirmed == false)
1404 			res_OPEN4->OPEN4res_u.resok4.rflags |= OPEN4_RESULT_CONFIRM;
1405 	
1406 		res_OPEN4->OPEN4res_u.resok4.rflags |= OPEN4_RESULT_LOCKTYPE_POSIX;
1407 	
1408 		LogFullDebug(COMPONENT_STATE, "NFS4 OPEN returning NFS4_OK");
1409 	
1410 		/* regular exit */
1411 		res_OPEN4->status = NFS4_OK;
1412 	
1413 		/* Update change_info4 */
1414 		res_OPEN4->OPEN4res_u.resok4.cinfo.after =
1415 			fsal_get_changeid4(obj_change);
1416 		res_OPEN4->OPEN4res_u.resok4.cinfo.atomic = FALSE;
1417 	
1418 		/* Handle open stateid/seqid for success */
1419 		update_stateid(file_state,
1420 			       &res_OPEN4->OPEN4res_u.resok4.stateid,
1421 			       data,
1422 			       open_tag);
1423 	
1424 	 out:
1425 	
1426 		if (res_OPEN4->status != NFS4_OK) {
1427 			LogDebug(COMPONENT_STATE, "failed with status %s",
1428 				 nfsstat4_to_str(res_OPEN4->status));
1429 		}
1430 	
1431 		/* Save the response in the open owner.
1432 		 * obj_change is either the parent directory or for a CLAIM_PREV is
1433 		 * the entry itself. In either case, it's the right entry to use in
1434 		 * saving the request results.
1435 		 */
1436 		if (data->minorversion == 0) {
1437 			Copy_nfs4_state_req(owner,
1438 					    arg_OPEN4->seqid,
1439 					    op,
1440 					    obj_change,
1441 					    resp,
1442 					    open_tag);
1443 		}
1444 	
1445 	 out2:
1446 		if (grace_ref)
1447 			nfs_put_grace_status();
1448 	
1449 		/* Update the lease before exit */
1450 		if (data->minorversion == 0) {
1451 			PTHREAD_MUTEX_lock(&clientid->cid_mutex);
1452 			update_lease(clientid);
1453 			PTHREAD_MUTEX_unlock(&clientid->cid_mutex);
1454 		}
1455 	
1456 		if (file_state != NULL)
1457 			dec_state_t_ref(file_state);
1458 	
1459 		/* Clean up if we have an error exit */
1460 		if ((file_state != NULL) && new_state &&
1461 		    (res_OPEN4->status != NFS4_OK)) {
1462 			/* Need to destroy open owner and state */
1463 			state_del(file_state);
1464 		}
1465 	
1466 		if (obj_change)
1467 			obj_change->obj_ops->put_ref(obj_change);
1468 	
1469 		if (owner != NULL) {
1470 			/* Need to release the open owner for this call */
1471 			dec_state_owner_ref(owner);
1472 		}
1473 	
1474 	 out3:
1475 	
1476 		dec_client_id_ref(clientid);
1477 	
1478 		return nfsstat4_to_nfs_req_result(res_OPEN4->status);
1479 	}				/* nfs4_op_open */
1480 	
1481 	/**
1482 	 * @brief Free memory allocated for OPEN result
1483 	 *
1484 	 * This function frees any memory allocated for the result of the
1485 	 * NFS4_OP_OPEN function.
1486 	 *
1487 	 * @param[in,out] resp nfs4_op results
1488 	 */
1489 	void nfs4_op_open_Free(nfs_resop4 *resp)
1490 	{
1491 		/* Nothing to be done */
1492 	}
1493