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
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