1 /*
2 * vim:noexpandtab:shiftwidth=8:tabstop=8:
3 *
4 * Copyright (C) Red Hat Inc., 2011
5 * Author: Anand Subramanian anands@redhat.com
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * -------------
22 */
23
24 /* main.c
25 * Module core functions
26 */
27
28 #include <sys/types.h>
29 #include "os/xattr.h"
30 #include "gluster_internal.h"
31 #include "fsal_api.h"
32 #include "fsal_convert.h"
33 #include "nfs4_acls.h"
34 #include "FSAL/fsal_commonlib.h"
35 #include "posix_acls.h"
36 #include "nfs_exports.h"
37
38 /**
39 * @brief FSAL status mapping from GlusterFS errors
40 *
41 * This function returns a fsal_status_t with the FSAL error as the
42 * major, and the posix error as minor. Please note that this routine
43 * needs to be used only in case of failures.
44 *
45 * @param[in] gluster_errorcode Gluster error
46 *
47 * @return FSAL status.
48 */
49
50 fsal_status_t gluster2fsal_error(const int err)
51 {
52 fsal_status_t status;
53 int g_err = err;
54
55 if (!g_err) {
56 LogWarn(COMPONENT_FSAL, "appropriate errno not set");
57 g_err = EINVAL;
58 }
59 status.minor = g_err;
60 status.major = posix2fsal_error(g_err);
61
62 return status;
63 }
64
65 /**
66 * @brief Convert a struct stat from Gluster to a struct attrlist
67 *
68 * This function writes the content of the supplied struct stat to the
69 * struct fsalsattr.
70 *
71 * @param[in] buffstat Stat structure
72 * @param[out] fsalattr FSAL attributes
73 */
74
75 void stat2fsal_attributes(const struct stat *buffstat,
76 struct attrlist *fsalattr)
77 {
78 /* Indicate which atrributes we have set without affecting the
79 * other bits in the mask.
80 */
81 fsalattr->valid_mask |= ATTRS_POSIX;
82 fsalattr->supported = op_ctx->fsal_export->exp_ops.fs_supported_attrs(
83 op_ctx->fsal_export);
84
85 /* Fills the output struct */
86 fsalattr->type = posix2fsal_type(buffstat->st_mode);
87
88 fsalattr->filesize = buffstat->st_size;
89
90 fsalattr->fsid = posix2fsal_fsid(buffstat->st_dev);
91
92 fsalattr->fileid = buffstat->st_ino;
93
94 fsalattr->mode = unix2fsal_mode(buffstat->st_mode);
95
96 fsalattr->numlinks = buffstat->st_nlink;
97
98 fsalattr->owner = buffstat->st_uid;
99
100 fsalattr->group = buffstat->st_gid;
101
102 /** @todo: gfapi currently only fills in the legacy time_t fields
103 * when it supports the timespec fields calls to this
104 * function should be replaced with calls to
105 * posix2fsal_attributes rather than changing this code.
106 */
107 fsalattr->atime = posix2fsal_time(buffstat->st_atime, 0);
108 fsalattr->ctime = posix2fsal_time(buffstat->st_ctime, 0);
109 fsalattr->mtime = posix2fsal_time(buffstat->st_mtime, 0);
110
111 fsalattr->change = MAX(buffstat->st_mtime, buffstat->st_ctime);
112
113 fsalattr->spaceused = buffstat->st_blocks * S_BLKSIZE;
114
115 fsalattr->rawdev = posix2fsal_devt(buffstat->st_rdev);
116
117 /* Disable seclabels if not enabled in config */
118 if (!op_ctx_export_has_option(EXPORT_OPTION_SECLABEL_SET))
119 fsalattr->supported &= ~ATTR4_SEC_LABEL;
120 }
121
122 /**
123 * @brief Construct a new filehandle
124 *
125 * This function constructs a new Gluster FSAL object handle and attaches
126 * it to the export. After this call the attributes have been filled
127 * in and the handdle is up-to-date and usable.
128 *
129 * @param[in] st Stat data for the file
130 * @param[in] export Export on which the object lives
131 * @param[out] obj Object created
132 *
133 * @return 0 on success, negative error codes on failure.
134 */
135
136 void construct_handle(struct glusterfs_export *glexport, const struct stat *st,
137 struct glfs_object *glhandle, unsigned char *globjhdl,
138 struct glusterfs_handle **obj, const char *vol_uuid)
139 {
140 struct glusterfs_handle *constructing = NULL;
141
142 constructing = gsh_calloc(1, sizeof(struct glusterfs_handle));
143
144 constructing->glhandle = glhandle;
145 memcpy(constructing->globjhdl, vol_uuid, GLAPI_UUID_LENGTH);
146 memcpy(constructing->globjhdl+GLAPI_UUID_LENGTH, globjhdl,
147 GFAPI_HANDLE_LENGTH);
148 constructing->globalfd.glfd = NULL;
149
150 fsal_obj_handle_init(&constructing->handle, &glexport->export,
151 posix2fsal_type(st->st_mode));
152 constructing->handle.fsid = posix2fsal_fsid(st->st_dev);
153 constructing->handle.fileid = st->st_ino;
154 constructing->handle.obj_ops = &GlusterFS.handle_ops;
155
156 *obj = constructing;
157 }
158
159 void gluster_cleanup_vars(struct glfs_object *glhandle)
160 {
161 if (glhandle) {
162 /* Error ignored, this is a cleanup operation, can't do much. */
163 /** @todo: Useful point for logging? */
164 glfs_h_close(glhandle);
165 }
166 }
167
168 /* fs_specific_has() parses the fs_specific string for a particular key,
169 * returns true if found, and optionally returns a val if the string is
170 * of the form key=val.
171 *
172 * The fs_specific string is a comma (,) separated options where each option
173 * can be of the form key=value or just key. Example:
174 * FS_specific = "foo=baz,enable_A";
175 */
176 bool fs_specific_has(const char *fs_specific, const char *key, char *val,
177 int *max_val_bytes)
178 {
179 char *next_comma, *option;
180 bool ret;
181 char *fso_dup = NULL;
182
183 if (!fs_specific || !fs_specific[0])
184 return false;
185
186 fso_dup = gsh_strdup(fs_specific);
187
188 for (option = strtok_r(fso_dup, ",", &next_comma); option;
189 option = strtok_r(NULL, ",", &next_comma)) {
190 char *k = option;
191 char *v = k;
192
193 strsep(&v, "=");
194 if (strcmp(k, key) == 0) {
195 if (val)
196 strncpy(val, v, *max_val_bytes);
197 if (max_val_bytes)
198 *max_val_bytes = strlen(v) + 1;
199 ret = true;
200 goto cleanup;
201 }
202 }
203
204 ret = false;
205 cleanup:
206 gsh_free(fso_dup);
207 return ret;
208 }
209
210 void setglustercreds(struct glusterfs_export *glfs_export, uid_t *uid,
211 gid_t *gid, unsigned int ngrps, gid_t *groups,
212 char *client_addr, unsigned int client_addr_len,
213 char *file, int line, char *function)
214 {
215 int rc = 0;
216 #ifdef USE_GLUSTER_DELEGATION
217 char lease_id[GLAPI_LEASE_ID_SIZE];
218 #endif
219
220 if (uid) {
221 if (*uid != glfs_export->saveduid)
222 rc = glfs_setfsuid(*uid);
223 } else {
224 rc = glfs_setfsuid(glfs_export->saveduid);
225 }
226 if (rc)
227 goto out;
228
229 if (gid) {
230 if (*gid != glfs_export->savedgid)
231 rc = glfs_setfsgid(*gid);
232 } else {
233 rc = glfs_setfsgid(glfs_export->savedgid);
234 }
235 if (rc)
236 goto out;
237
238 if (ngrps != 0 && groups)
239 rc = glfs_setfsgroups(ngrps, groups);
240 else
241 rc = glfs_setfsgroups(0, NULL);
242
243 #ifdef USE_GLUSTER_DELEGATION
244 if ((client_addr_len <= GLAPI_LEASE_ID_SIZE) && client_addr) {
245 memset(lease_id, 0, GLFS_LEASE_ID_SIZE);
246 memcpy(lease_id, client_addr, client_addr_len);
247 rc = glfs_setfsleaseid(lease_id);
248 } else
249 rc = glfs_setfsleaseid(NULL);
250 #endif
251 out:
252 if (rc != 0) {
253 DisplayLogComponentLevel(COMPONENT_FSAL, file, line, function,
254 NIV_FATAL,
255 "Could not set Gluster credentials - uid(%d), gid(%d)",
256 uid ? *uid : glfs_export->saveduid,
257 gid ? *gid : glfs_export->savedgid);
258 }
259 }
260
261 /*
262 * Read the ACL in GlusterFS format and convert it into fsal ACL before
263 * storing it in fsalattr
264 */
265 fsal_status_t glusterfs_get_acl(struct glusterfs_export *glfs_export,
266 struct glfs_object *glhandle,
267 glusterfs_fsal_xstat_t *buffxstat,
268 struct attrlist *fsalattr)
269 {
270 fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
271 fsal_acl_data_t acldata;
272 fsal_acl_status_t aclstatus;
273 fsal_ace_t *pace = NULL;
274 int e_count = 0, i_count = 0, new_count = 0, new_i_count = 0;
275
276 if (fsalattr->acl != NULL) {
277 /* We should never be passed attributes that have an
278 * ACL attached, but just in case some future code
279 * path changes that assumption, let's release the
280 * old ACL properly.
281 */
282 int acl_status;
283
284 acl_status = nfs4_acl_release_entry(fsalattr->acl);
285
286 if (acl_status != NFS_V4_ACL_SUCCESS)
287 LogCrit(COMPONENT_FSAL,
288 "Failed to release old acl, status=%d",
289 acl_status);
290
291 fsalattr->acl = NULL;
292 }
293
294 if (NFSv4_ACL_SUPPORT) {
295
296 buffxstat->e_acl = glfs_h_acl_get(glfs_export->gl_fs->fs,
297 glhandle, ACL_TYPE_ACCESS);
298
299 if (!buffxstat->e_acl) {
300 status = gluster2fsal_error(errno);
301 return status;
302 }
303
304 e_count = ace_count(buffxstat->e_acl);
305
306 if (buffxstat->is_dir) {
307 buffxstat->i_acl =
308 glfs_h_acl_get(glfs_export->gl_fs->fs,
309 glhandle, ACL_TYPE_DEFAULT);
310 i_count = ace_count(buffxstat->i_acl);
311 }
312
313 /* Allocating memory for both ALLOW and DENY entries */
314 acldata.naces = 2 * (e_count + i_count);
315
316 LogDebug(COMPONENT_FSAL, "No of aces present in fsal_acl_t = %d"
317 , acldata.naces);
318 if (!acldata.naces)
319 return status;
320
321 FSAL_SET_MASK(buffxstat->attr_valid, XATTR_ACL);
322
323 acldata.aces = (fsal_ace_t *) nfs4_ace_alloc(acldata.naces);
324 pace = acldata.aces;
325
326 new_count = posix_acl_2_fsal_acl(buffxstat->e_acl,
327 buffxstat->is_dir, false, &pace);
328 if (new_count < 0)
329 return fsalstat(ERR_FSAL_NO_ACE, -1);
330
331 if (i_count > 0) {
332 new_i_count = posix_acl_2_fsal_acl(buffxstat->i_acl,
333 true, true, &pace);
334 if (new_i_count > 0)
335 new_count += new_i_count;
336 else
337 LogDebug(COMPONENT_FSAL,
338 "Inherit acl is not set for this directory");
339 }
340
341 /* Reallocating acldata into the required size */
342 acldata.aces = (fsal_ace_t *) gsh_realloc(acldata.aces,
343 new_count*sizeof(fsal_ace_t));
344 acldata.naces = new_count;
345
346 fsalattr->acl = nfs4_acl_new_entry(&acldata, &aclstatus);
347 LogDebug(COMPONENT_FSAL, "fsal acl = %p, fsal_acl_status = %u",
348 fsalattr->acl, aclstatus);
349 if (fsalattr->acl == NULL) {
350 LogCrit(COMPONENT_FSAL,
351 "failed to create a new acl entry");
352 return fsalstat(ERR_FSAL_NOMEM, -1);
353 }
354
355 fsalattr->valid_mask |= ATTR_ACL;
356 } else {
357 /* We were asked for ACL but do not support. */
358 status = fsalstat(ERR_FSAL_NOTSUPP, 0);
359 }
360
361 return status;
362
363 }
364
365 /*
366 * Store the Glusterfs ACL using setxattr call.
367 */
368 fsal_status_t glusterfs_set_acl(struct glusterfs_export *glfs_export,
369 struct glusterfs_handle *objhandle,
370 glusterfs_fsal_xstat_t *buffxstat)
371 {
372 int rc = 0;
373
374 rc = glfs_h_acl_set(glfs_export->gl_fs->fs, objhandle->glhandle,
375 ACL_TYPE_ACCESS, buffxstat->e_acl);
376 if (rc < 0) {
377 /** @todo: check if error is appropriate.*/
378 LogMajor(COMPONENT_FSAL, "failed to set access type posix acl");
379 return fsalstat(ERR_FSAL_INVAL, 0);
380 }
381 /* For directories consider inherited acl too */
382 if (buffxstat->is_dir && buffxstat->i_acl) {
383 rc = glfs_h_acl_set(glfs_export->gl_fs->fs, objhandle->glhandle,
384 ACL_TYPE_DEFAULT, buffxstat->i_acl);
385 if (rc < 0) {
386 LogMajor(COMPONENT_FSAL,
387 "failed to set default type posix acl");
388 return fsalstat(ERR_FSAL_INVAL, 0);
389 }
390 }
391 return fsalstat(ERR_FSAL_NO_ERROR, 0);
392 }
393
394 /*
395 * Process NFSv4 ACLs passed in setattr call
396 */
397 fsal_status_t glusterfs_process_acl(struct glfs *fs,
398 struct glfs_object *object,
399 struct attrlist *attrs,
400 glusterfs_fsal_xstat_t *buffxstat)
401 {
402 LogDebug(COMPONENT_FSAL, "setattr acl = %p", attrs->acl);
403
404 /* Convert FSAL ACL to POSIX ACL */
405 buffxstat->e_acl = fsal_acl_2_posix_acl(attrs->acl, ACL_TYPE_ACCESS);
406 if (!buffxstat->e_acl) {
407 LogMajor(COMPONENT_FSAL,
408 "failed to set access type posix acl");
409 return fsalstat(ERR_FSAL_FAULT, 0);
410 }
411 /* For directories consider inherited acl too */
412 if (buffxstat->is_dir) {
413 buffxstat->i_acl = fsal_acl_2_posix_acl(attrs->acl,
414 ACL_TYPE_DEFAULT);
415 if (!buffxstat->i_acl)
416 LogDebug(COMPONENT_FSAL,
417 "inherited acl is not defined for directory");
418 }
419
420 return fsalstat(ERR_FSAL_NO_ERROR, 0);
421 }
422
423 int initiate_up_thread(struct glusterfs_fs *gl_fs)
424 {
425
426 pthread_attr_t up_thr_attr;
427 int retval = -1;
428 int err = 0;
429 int retries = 10;
430
431 memset(&up_thr_attr, 0, sizeof(up_thr_attr));
432
433 /* Initialization of thread attributes from nfs_init.c */
434 err = pthread_attr_init(&up_thr_attr);
435 if (err) {
436 LogCrit(COMPONENT_THREAD,
437 "can't init pthread's attributes (%s)",
438 strerror(err));
439 goto out;
440 }
441
442 err = pthread_attr_setscope(&up_thr_attr,
443 PTHREAD_SCOPE_SYSTEM);
444 if (err) {
445 LogCrit(COMPONENT_THREAD,
446 "can't set pthread's scope (%s)",
447 strerror(err));
448 goto out;
449 }
450
451 err = pthread_attr_setdetachstate(&up_thr_attr,
452 PTHREAD_CREATE_JOINABLE);
453 if (err) {
454 LogCrit(COMPONENT_THREAD,
455 "can't set pthread's join state (%s)",
456 strerror(err));
457 goto out;
458 }
459
460 err = pthread_attr_setstacksize(&up_thr_attr, 2116488);
461 if (err) {
462 LogCrit(COMPONENT_THREAD,
463 "can't set pthread's stack size (%s)",
464 strerror(err));
465 goto out;
466 }
467
468 do {
469 err = pthread_create(&gl_fs->up_thread,
470 &up_thr_attr,
471 GLUSTERFSAL_UP_Thread,
472 gl_fs);
473 sleep(1);
474 } while (err && (err == EAGAIN) && (retries-- > 0));
475
476 if (err) {
477 LogCrit(COMPONENT_THREAD,
478 "can't create upcall pthread (%s)",
479 strerror(err));
480 goto out;
481 }
482
483 retval = 0;
484
485 out:
486 err = pthread_attr_destroy(&up_thr_attr);
487 if (err) {
488 LogCrit(COMPONENT_THREAD,
489 "can't destroy pthread's attributes (%s)",
490 strerror(err));
491 }
492
493 return retval;
494 }
495
496 #ifdef GLTIMING
497 void latency_update(struct timespec *s_time, struct timespec *e_time, int opnum)
498 {
499 atomic_add_uint64_t(&glfsal_latencies[opnum].overall_time,
500 timespec_diff(s_time, e_time));
501 atomic_add_uint64_t(&glfsal_latencies[opnum].count, 1);
502 }
503
504 void latency_dump(void)
505 {
506 int i = 0;
507
508 for (; i < LATENCY_SLOTS; i++) {
509 LogCrit(COMPONENT_FSAL, "Op:%d:Count:%"PRIu64":nsecs:%"PRIu64,
510 i, glfsal_latencies[i].count,
511 glfsal_latencies[i].overall_time);
512 }
513 }
514 #endif
515