1    	/*
2    	 * vim:noexpandtab:shiftwidth=8:tabstop=8:
3    	 *
4    	 * Copyright (C) Red Hat  Inc., 2014
5    	 * Author: Jiffin Tony Thottan jthottan@redhat.com
6    	 *       : Anand Subramanian   anands@redhat.com
7    	 *
8    	 * This program is free software; you can redistribute it and/or
9    	 * modify it under the terms of the GNU Lesser General Public
10   	 * License as published by the Free Software Foundation; either
11   	 * version 3 of the License, or (at your option) any later version.
12   	 *
13   	 * This program is distributed in the hope that it will be useful,
14   	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   	 * Lesser General Public License for more details.
17   	 *
18   	 * You should have received a copy of the GNU Lesser General Public
19   	 * License along with this library; if not, write to the Free Software
20   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
21   	 *
22   	 * -------------
23   	 */
24   	#include <fcntl.h>
25   	#include "fsal.h"
26   	#include "fsal_types.h"
27   	#include "fsal_api.h"
28   	#include "fsal_up.h"
29   	#include "gluster_internal.h"
30   	#include "FSAL/fsal_commonlib.h"
31   	#include "fsal_convert.h"
32   	#include "pnfs_utils.h"
33   	#include "nfs_exports.h"
34   	#include <arpa/inet.h>
35   	#include "../fsal_private.h"
36   	
37   	/**
38   	 * @brief Release a DS object
39   	 *
40   	 * @param[in] obj_pub The object to release
41   	 *
42   	 * @return NFS Status codes.
43   	 */
44   	static void release(struct fsal_ds_handle *const ds_pub)
45   	{
46   		int    rc                 = 0;
47   		struct glfs_ds_handle *ds =
48   			container_of(ds_pub, struct glfs_ds_handle, ds);
49   	
50   		fsal_ds_handle_fini(&ds->ds);
51   		if (ds->glhandle) {
52   			rc = glfs_h_close(ds->glhandle);
53   			if (rc) {
54   				LogMajor(COMPONENT_PNFS,
55   					 "glfs_h_close returned error %s(%d)",
56   					 strerror(errno), errno);
57   			}
58   		}
59   		gsh_free(ds);
60   	}
61   	
62   	/**
63   	 * @brief Read from a data-server handle.
64   	 *
65   	 * NFSv4.1 data server handles are disjount from normal
66   	 * filehandles (in Ganesha, there is a ds_flag in the filehandle_v4_t
67   	 * structure) and do not get loaded into cache_inode or processed the
68   	 * normal way.
69   	 *
70   	 * @param[in]  ds_pub           FSAL DS handle
71   	 * @param[in]  req_ctx          Credentials
72   	 * @param[in]  stateid          The stateid supplied with the READ operation,
73   	 *                              for validation
74   	 * @param[in]  offset           The offset at which to read
75   	 * @param[in]  requested_length Length of read requested (and size of buffer)
76   	 * @param[out] buffer           The buffer to which to store read data
77   	 * @param[out] supplied_length  Length of data read
78   	 * @param[out] eof              True on end of file
79   	 *
80   	 * @return An NFSv4.1 status code.
81   	 */
82   	static nfsstat4 ds_read(struct fsal_ds_handle *const ds_pub,
83   				struct req_op_context *const req_ctx,
84   				const stateid4 *stateid, const offset4 offset,
85   				const count4 requested_length, void *const buffer,
86   				count4 * const supplied_length,
87   				bool * const end_of_file)
88   	{
89   		/* The private DS handle */
90   		struct glfs_ds_handle *ds =
91   			container_of(ds_pub, struct glfs_ds_handle, ds);
92   		int    rc = 0;
93   		struct glusterfs_export *glfs_export =
94   		container_of(ds_pub->pds->mds_fsal_export,
95   			     struct glusterfs_export, export);
96   	
97   		if (ds->glhandle == NULL)
98   			LogDebug(COMPONENT_PNFS, "glhandle NULL");
99   	
100  		rc = glfs_h_anonymous_read(glfs_export->gl_fs->fs, ds->glhandle,
101  					   buffer, requested_length, offset);
102  		if (rc < 0) {
103  			rc = errno;
104  			LogMajor(COMPONENT_PNFS, "Read failed on DS");
105  			return posix2nfs4_error(rc);
106  		}
107  	
108  		*supplied_length = rc;
109  		if (rc == 0 || rc < requested_length)
110  			*end_of_file = true;
111  	
112  	
113  		return NFS4_OK;
114  	}
115  	
116  	/**
117  	 *
118  	 * @brief Write to a data-server handle.
119  	 *
120  	 * @param[in]  ds_pub           FSAL DS handle
121  	 * @param[in]  req_ctx          Credentials
122  	 * @param[in]  stateid          The stateid supplied with the READ operation,
123  	 *                              for validation
124  	 * @param[in]  offset           The offset at which to read
125  	 * @param[in]  write_length     Length of write requested (and size of buffer)
126  	 * @param[out] buffer           The buffer to which to store read data
127  	 * @param[in]  stability wanted Stability of write
128  	 * @param[out] written_length   Length of data written
129  	 * @param[out] writeverf        Write verifier
130  	 * @param[out] stability_got    Stability used for write (must be as
131  	 *                              or more stable than request)
132  	 *
133  	 * @return An NFSv4.1 status code.
134  	 */
135  	static nfsstat4 ds_write(struct fsal_ds_handle *const ds_pub,
136  				 struct req_op_context *const req_ctx,
137  				 const stateid4 *stateid, const offset4 offset,
138  				 const count4 write_length, const void *buffer,
139  				 const stable_how4 stability_wanted,
140  				 count4 * const written_length,
141  				 verifier4 * const writeverf,
142  				 stable_how4 * const stability_got)
143  	{
144  		struct glfs_ds_handle *ds =
145  			container_of(ds_pub, struct glfs_ds_handle, ds);
146  		struct glusterfs_export *glfs_export =
147  		container_of(ds_pub->pds->mds_fsal_export,
148  			     struct glusterfs_export, export);
149  		int    rc = 0;
150  	
151  		memset(writeverf, 0, NFS4_VERIFIER_SIZE);
152  	
153  		if (ds->glhandle == NULL)
154  			LogDebug(COMPONENT_PNFS, "glhandle NULL");
155  	
156  		rc = glfs_h_anonymous_write(glfs_export->gl_fs->fs, ds->glhandle,
157  					    buffer, write_length, offset);
158  		if (rc < 0) {
159  			rc = errno;
160  			LogMajor(COMPONENT_PNFS, "status after write %d", rc);
161  			return posix2nfs4_error(rc);
162  		}
163  	
164  		/** @todo:Here DS is performing the write operation, so the MDS is not
165  		 *      aware of the change.We should inform MDS through upcalls about
166  		 *      change in file attributes such as size and time.
167  		 */
168  		*written_length = rc;
169  	
170  		*stability_got = stability_wanted;
171  		ds->stability_got = stability_wanted;
172  	
173  		/* Incase of MDS being DS, there shall not be upcalls sent from
174  		 * backend. Hence invalidate the entry here */
175  		(void)up_process_event_object(glfs_export->gl_fs, ds->glhandle,
176  					      GLFS_EVENT_INODE_INVALIDATE);
177  	
178  		return NFS4_OK;
179  	}
180  	
181  	/**
182  	 * @brief Commit a byte range to a DS handle.
183  	 *
184  	 * NFSv4.1 data server filehandles are disjount from normal
185  	 * filehandles (in Ganesha, there is a ds_flag in the filehandle_v4_t
186  	 * structure) and do not get loaded into cache_inode or processed the
187  	 * normal way.
188  	 *
189  	 * @param[in]  ds_pub    FSAL DS handle
190  	 * @param[in]  req_ctx   Credentials
191  	 * @param[in]  offset    Start of commit window
192  	 * @param[in]  count     Length of commit window
193  	 * @param[out] writeverf Write verifier
194  	 *
195  	 * @return An NFSv4.1 status code.
196  	 */
197  	static nfsstat4 ds_commit(struct fsal_ds_handle *const ds_pub,
198  				  struct req_op_context *const req_ctx,
199  				  const offset4 offset, const count4 count,
200  				  verifier4 * const writeverf)
201  	{
202  		memset(writeverf, 0, NFS4_VERIFIER_SIZE);
203  		struct glfs_ds_handle *ds =
204  			container_of(ds_pub, struct glfs_ds_handle, ds);
205  		int rc = 0;
206  		fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
207  	
208  		if (ds->stability_got == FILE_SYNC4) {
209  			struct glusterfs_export *glfs_export =
210  				container_of(ds_pub->pds->mds_fsal_export,
211  					     struct glusterfs_export, export);
212  			struct glfs_fd *glfd = NULL;
213  	
214  			SET_GLUSTER_CREDS(glfs_export, &op_ctx->creds->caller_uid,
215  					  &op_ctx->creds->caller_gid,
216  					  op_ctx->creds->caller_glen,
217  					  op_ctx->creds->caller_garray,
218  					  op_ctx->client->addr.addr,
219  					  op_ctx->client->addr.len);
220  	
221  			glfd = glfs_h_open(glfs_export->gl_fs->fs, ds->glhandle,
222  					   O_RDWR);
223  			if (glfd == NULL) {
224  				LogDebug(COMPONENT_PNFS, "glfd in ds_handle is NULL");
225  				SET_GLUSTER_CREDS(glfs_export, NULL, NULL, 0, NULL,
226  						  NULL, 0);
227  				return NFS4ERR_SERVERFAULT;
228  			}
229  	#ifdef USE_GLUSTER_STAT_FETCH_API
230  			rc = glfs_fsync(glfd, NULL, NULL);
231  	#else
232  			rc = glfs_fsync(glfd);
233  	#endif
234  			if (rc != 0)
235  				LogMajor(COMPONENT_PNFS,
236  					 "glfs_fsync failed %d", errno);
237  			rc = glfs_close(glfd);
238  			if (rc != 0)
239  				LogDebug(COMPONENT_PNFS,
240  					 "status after close %d", errno);
241  	
242  			SET_GLUSTER_CREDS(glfs_export, NULL, NULL, 0, NULL, NULL, 0);
243  		}
244  	
245  		if ((rc != 0) || (status.major != ERR_FSAL_NO_ERROR))
246  			return NFS4ERR_INVAL;
247  	
248  		return NFS4_OK;
249  	}
250  	
251  	/* Initialise DS operations */
252  	void dsh_ops_init(struct fsal_dsh_ops *ops)
253  	{
254  		ops->release = release;
255  		ops->read = ds_read;
256  		ops->write = ds_write;
257  		ops->commit = ds_commit;
258  	};
259  	
260  	/**
261  	 * @brief Create a FSAL data server handle from a wire handle
262  	 *
263  	 * This function creates a FSAL data server handle from a client
264  	 * supplied "wire" handle.  This is also where validation gets done,
265  	 * since PUTFH is the only operation that can return
266  	 * NFS4ERR_BADHANDLE.
267  	 *
268  	 * @param[in]  export_pub The export in which to create the handle
269  	 * @param[in]  desc       Buffer from which to create the file
270  	 * @param[out] ds_pub     FSAL data server handle
271  	 *
272  	 * @return NFSv4.1 error codes.
273  	 */
274  	static nfsstat4 make_ds_handle(struct fsal_pnfs_ds *const pds,
275  				       const struct gsh_buffdesc *const hdl_desc,
276  				       struct fsal_ds_handle **const handle,
277  				       int flags)
278  	{
279  	
280  		/* Handle to be created for DS */
281  		struct glfs_ds_handle *ds                   = NULL;
282  		unsigned char globjhdl[GFAPI_HANDLE_LENGTH] = {'\0'};
283  		struct stat sb;
284  		struct glusterfs_export *glfs_export =
285  			container_of(pds->mds_fsal_export,
286  				     struct glusterfs_export, export);
287  	
288  		*handle = NULL;
289  	
290  		if (hdl_desc->len != sizeof(struct glfs_ds_wire))
291  			return NFS4ERR_BADHANDLE;
292  	
(2) Event example_assign: Example 1: Assigning: "p_" = return value from "calloc(1UL, 88UL)".
(3) Event example_checked: Example 1 (cont.): "p_" has its value checked in "p_ == NULL".
Also see events: [returned_null][example_assign][example_checked][example_assign][example_checked][example_assign][example_checked][example_assign][example_checked][var_assigned][dereference]
293  		ds = gsh_calloc(1, sizeof(struct glfs_ds_handle));
294  	
295  		*handle = &ds->ds;
296  		fsal_ds_handle_init(*handle, pds);
297  	
298  		memcpy(globjhdl, hdl_desc->addr, GFAPI_HANDLE_LENGTH);
299  	
300  		/* Create glfs_object for the DS handle */
301  		ds->glhandle =	glfs_h_create_from_handle(glfs_export->gl_fs->fs,
302  							  globjhdl,
303  							  GFAPI_HANDLE_LENGTH, &sb);
304  		if (ds->glhandle == NULL) {
305  			LogDebug(COMPONENT_PNFS,
306  				 "glhandle in ds_handle is NULL");
307  			return NFS4ERR_SERVERFAULT;
308  		}
309  	
310  		/* Connect lazily when a FILE_SYNC4 write forces us to, not
311  		   here. */
312  	
313  		ds->connected = false;
314  	
315  		return NFS4_OK;
316  	}
317  	
318  	void pnfs_ds_ops_init(struct fsal_pnfs_ds_ops *ops)
319  	{
320  		memcpy(ops, &def_pnfs_ds_ops, sizeof(struct fsal_pnfs_ds_ops));
321  		ops->make_ds_handle = make_ds_handle;
322  		ops->fsal_dsh_ops = dsh_ops_init;
323  	}
324