1 /*
2    Copyright 2017 Skytechnology sp. z o.o.
3 
4    This file is part of LizardFS.
5 
6    LizardFS is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, version 3.
9 
10    LizardFS is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with LizardFS. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <stdint.h>
20 
21 #include "fsal.h"
22 #include "fsal_api.h"
23 #include "fsal_convert.h"
24 #include "fsal_types.h"
25 
26 #include "common/lizardfs_error_codes.h"
27 #include "context_wrap.h"
28 #include "lzfs_internal.h"
29 
30 /*! \brief Clean up a filehandle
31  *
32  * \see fsal_api.h for more information
33  */
lzfs_fsal_release(struct fsal_obj_handle * obj_hdl)34 static void lzfs_fsal_release(struct fsal_obj_handle *obj_hdl) {
35 	struct lzfs_fsal_handle *lzfs_obj = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
36 
37 	if (lzfs_obj != lzfs_obj->export->root) {
38 		lzfs_fsal_delete_handle(lzfs_obj);
39 	}
40 }
41 
42 /*! \brief Look up a filename
43  *
44  * \see fsal_api.h for more information
45  */
lzfs_fsal_lookup(struct fsal_obj_handle * dir_hdl,const char * path,struct fsal_obj_handle ** obj_hdl,struct attrlist * attrs_out)46 static fsal_status_t lzfs_fsal_lookup(struct fsal_obj_handle *dir_hdl, const char *path,
47                                       struct fsal_obj_handle **obj_hdl,
48                                       struct attrlist *attrs_out) {
49 	struct lzfs_fsal_export *lzfs_export;
50 	struct lzfs_fsal_handle *lzfs_obj, *lzfs_dir;
51 	struct liz_entry node;
52 	int rc;
53 
54 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
55 	lzfs_dir = container_of(dir_hdl, struct lzfs_fsal_handle, handle);
56 
57 	LogFullDebug(COMPONENT_FSAL, "path=%s", path);
58 
59 	rc = liz_cred_lookup(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_dir->inode, path, &node);
60 
61 	if (rc < 0) {
62 		return lzfs_fsal_last_err();
63 	}
64 
65 	lzfs_obj = lzfs_fsal_new_handle(&node.attr, lzfs_export);
66 
67 	if (attrs_out != NULL) {
68 		posix2fsal_attributes_all(&node.attr, attrs_out);
69 	}
70 
71 	*obj_hdl = &lzfs_obj->handle;
72 
73 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
74 }
75 
76 /*! \brief Read a directory
77  *
78  * \see fsal_api.h for more information
79  */
lzfs_fsal_readdir(struct fsal_obj_handle * dir_hdl,fsal_cookie_t * whence,void * dir_state,fsal_readdir_cb cb,attrmask_t attrmask,bool * eof)80 static fsal_status_t lzfs_fsal_readdir(struct fsal_obj_handle *dir_hdl, fsal_cookie_t *whence,
81                                        void *dir_state, fsal_readdir_cb cb, attrmask_t attrmask,
82                                        bool *eof) {
83 	static const int kBatchSize = 100;
84 
85 	struct lzfs_fsal_export *lzfs_export;
86 	struct lzfs_fsal_handle *lzfs_dir, *lzfs_obj;
87 	struct liz_direntry buffer[kBatchSize];
88 	struct liz_fileinfo *dir_desc;
89 	struct attrlist attrs;
90 	off_t direntry_offset = 2;
91 	enum fsal_dir_result cb_rc;
92 	int rc;
93 
94 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
95 	lzfs_dir = container_of(dir_hdl, struct lzfs_fsal_handle, handle);
96 
97 	liz_context_t *ctx = lzfs_fsal_create_context(lzfs_export->lzfs_instance, op_ctx->creds);
98 	dir_desc = liz_opendir(lzfs_export->lzfs_instance, ctx, lzfs_dir->inode);
99 	if (!dir_desc) {
100 		liz_destroy_context(ctx);
101 		return lzfs_fsal_last_err();
102 	}
103 
104 	if (whence != NULL) {
105 		direntry_offset = MAX(3, *whence) - 1;
106 	}
107 
108 	LogFullDebug(COMPONENT_FSAL, "export=%" PRIu16 " inode=%" PRIu32 " offset=%lli",
109 	             lzfs_export->export.export_id, lzfs_dir->inode, (long long)direntry_offset);
110 
111 	while (1) {
112 		size_t i, entries_count = 0;
113 
114 		rc = liz_readdir(lzfs_export->lzfs_instance, ctx, dir_desc, direntry_offset, kBatchSize,
115 		                 buffer, &entries_count);
116 		if (rc < 0) {
117 			liz_destroy_context(ctx);
118 			return lzfs_fsal_last_err();
119 		}
120 
121 		cb_rc = DIR_CONTINUE;
122 		for (i = 0; i < entries_count && cb_rc != DIR_TERMINATE; ++i) {
123 			lzfs_obj = lzfs_fsal_new_handle(&buffer[i].attr, lzfs_export);
124 
125 			fsal_prepare_attrs(&attrs, attrmask);
126 			posix2fsal_attributes_all(&buffer[i].attr, &attrs);
127 
128 			direntry_offset = buffer[i].next_entry_offset;
129 			cb_rc = cb(buffer[i].name, &lzfs_obj->handle, &attrs, dir_state, direntry_offset + 1);
130 
131 			fsal_release_attrs(&attrs);
132 		}
133 
134 		liz_destroy_direntry(buffer, entries_count);
135 
136 		*eof = entries_count < kBatchSize && i == entries_count;
137 
138 		if (cb_rc != DIR_CONTINUE || entries_count < kBatchSize) {
139 			break;
140 		}
141 	}
142 
143 	rc = liz_releasedir(lzfs_export->lzfs_instance, dir_desc);
144 	liz_destroy_context(ctx);
145 
146 	if (rc < 0) {
147 		return lzfs_fsal_last_err();
148 	}
149 
150 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
151 }
152 
153 /*! \brief Create a directory
154  *
155  * \see fsal_api.h for more information
156  */
lzfs_fsal_mkdir(struct fsal_obj_handle * dir_hdl,const char * name,struct attrlist * attrib,struct fsal_obj_handle ** new_obj,struct attrlist * attrs_out)157 static fsal_status_t lzfs_fsal_mkdir(struct fsal_obj_handle *dir_hdl, const char *name,
158                                      struct attrlist *attrib, struct fsal_obj_handle **new_obj,
159                                      struct attrlist *attrs_out) {
160 	struct lzfs_fsal_export *lzfs_export;
161 	struct lzfs_fsal_handle *lzfs_dir, *lzfs_obj;
162 	struct liz_entry dir_entry;
163 	mode_t unix_mode;
164 	fsal_status_t status;
165 	int rc;
166 
167 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
168 	lzfs_dir = container_of(dir_hdl, struct lzfs_fsal_handle, handle);
169 
170 	LogFullDebug(COMPONENT_FSAL,
171 	             "export=%" PRIu16 " parent_inode=%" PRIu32 " mode=%" PRIo32 " name=%s",
172 	             lzfs_export->export.export_id, lzfs_dir->inode, attrib->mode, name);
173 
174 	unix_mode =
175 	    fsal2unix_mode(attrib->mode) & ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export);
176 
177 	rc = liz_cred_mkdir(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_dir->inode, name, unix_mode,
178 	                    &dir_entry);
179 
180 	if (rc < 0) {
181 		return lzfs_fsal_last_err();
182 	}
183 
184 	lzfs_obj = lzfs_fsal_new_handle(&dir_entry.attr, lzfs_export);
185 	*new_obj = &lzfs_obj->handle;
186 
187 	FSAL_UNSET_MASK(attrib->valid_mask, ATTR_MODE);
188 
189 	if (attrib->valid_mask) {
190 		status = (*new_obj)->obj_ops.setattr2(*new_obj, false, NULL, attrib);
191 		if (FSAL_IS_ERROR(status)) {
192 			LogFullDebug(COMPONENT_FSAL, "setattr2 status=%s", fsal_err_txt(status));
193 			(*new_obj)->obj_ops.release(*new_obj);
194 			*new_obj = NULL;
195 		}
196 	} else {
197 		if (attrs_out != NULL) {
198 			posix2fsal_attributes_all(&dir_entry.attr, attrs_out);
199 		}
200 	}
201 
202 	FSAL_SET_MASK(attrib->valid_mask, ATTR_MODE);
203 
204 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
205 }
206 
207 /*! \brief Create a special file
208  *
209  * \see fsal_api.h for more information
210  */
lzfs_fsal_mknode(struct fsal_obj_handle * dir_hdl,const char * name,object_file_type_t nodetype,struct attrlist * attrib,struct fsal_obj_handle ** new_obj,struct attrlist * attrs_out)211 static fsal_status_t lzfs_fsal_mknode(struct fsal_obj_handle *dir_hdl, const char *name,
212                                       object_file_type_t nodetype, struct attrlist *attrib,
213                                       struct fsal_obj_handle **new_obj,
214                                       struct attrlist *attrs_out) {
215 	struct lzfs_fsal_export *lzfs_export;
216 	struct lzfs_fsal_handle *lzfs_dir, *lzfs_obj;
217 	struct liz_entry node_entry;
218 	mode_t unix_mode;
219 	dev_t unix_dev = 0;
220 	int rc;
221 
222 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
223 	lzfs_dir = container_of(dir_hdl, struct lzfs_fsal_handle, handle);
224 
225 	LogFullDebug(COMPONENT_FSAL,
226 	             "export=%" PRIu16 " parent_inode=%" PRIu32 " mode=%" PRIo32 " name=%s",
227 	             lzfs_export->export.export_id, lzfs_dir->inode, attrib->mode, name);
228 
229 	unix_mode =
230 	    fsal2unix_mode(attrib->mode) & ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export);
231 
232 	switch (nodetype) {
233 	case BLOCK_FILE:
234 		unix_mode |= S_IFBLK;
235 		unix_dev = makedev(attrib->rawdev.major, attrib->rawdev.minor);
236 		break;
237 	case CHARACTER_FILE:
238 		unix_mode |= S_IFCHR;
239 		unix_dev = makedev(attrib->rawdev.major, attrib->rawdev.minor);
240 		break;
241 	case FIFO_FILE:
242 		unix_mode |= S_IFIFO;
243 		break;
244 	case SOCKET_FILE:
245 		unix_mode |= S_IFSOCK;
246 		break;
247 	default:
248 		LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d", nodetype);
249 		return fsalstat(ERR_FSAL_INVAL, EINVAL);
250 	}
251 
252 	rc = liz_cred_mknod(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_dir->inode, name, unix_mode,
253 	                    unix_dev, &node_entry);
254 	if (rc < 0) {
255 		return lzfs_fsal_last_err();
256 	}
257 
258 	lzfs_obj = lzfs_fsal_new_handle(&node_entry.attr, lzfs_export);
259 	*new_obj = &lzfs_obj->handle;
260 
261 	// We handled the mode above.
262 	FSAL_UNSET_MASK(attrib->valid_mask, ATTR_MODE);
263 
264 	if (attrib->valid_mask) {
265 		fsal_status_t status = (*new_obj)->obj_ops.setattr2(*new_obj, false, NULL, attrib);
266 		if (FSAL_IS_ERROR(status)) {
267 			LogFullDebug(COMPONENT_FSAL, "setattr2 status=%s", fsal_err_txt(status));
268 			(*new_obj)->obj_ops.release(*new_obj);
269 			*new_obj = NULL;
270 		}
271 	} else {
272 		if (attrs_out != NULL) {
273 			posix2fsal_attributes_all(&node_entry.attr, attrs_out);
274 		}
275 	}
276 
277 	FSAL_SET_MASK(attrib->valid_mask, ATTR_MODE);
278 
279 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
280 }
281 
282 /*! \brief Create a symbolic link
283  *
284  * \see fsal_api.h for more information
285  */
lzfs_fsal_symlink(struct fsal_obj_handle * dir_hdl,const char * name,const char * link_path,struct attrlist * attrib,struct fsal_obj_handle ** new_obj,struct attrlist * attrs_out)286 static fsal_status_t lzfs_fsal_symlink(struct fsal_obj_handle *dir_hdl, const char *name,
287                                        const char *link_path, struct attrlist *attrib,
288                                        struct fsal_obj_handle **new_obj,
289                                        struct attrlist *attrs_out) {
290 	struct lzfs_fsal_export *lzfs_export;
291 	struct lzfs_fsal_handle *lzfs_dir, *lzfs_obj;
292 	struct liz_entry node_entry;
293 	int rc;
294 
295 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
296 	lzfs_dir = container_of(dir_hdl, struct lzfs_fsal_handle, handle);
297 
298 	LogFullDebug(COMPONENT_FSAL, "export=%" PRIu16 " parent_inode=%" PRIu32 " name=%s",
299 	             lzfs_export->export.export_id, lzfs_dir->inode, name);
300 
301 	rc = liz_cred_symlink(lzfs_export->lzfs_instance, op_ctx->creds, link_path, lzfs_dir->inode,
302 	                      name, &node_entry);
303 	if (rc < 0) {
304 		return lzfs_fsal_last_err();
305 	}
306 
307 	lzfs_obj = lzfs_fsal_new_handle(&node_entry.attr, lzfs_export);
308 	*new_obj = &lzfs_obj->handle;
309 
310 	FSAL_UNSET_MASK(attrib->valid_mask, ATTR_MODE);
311 
312 	if (attrib->valid_mask) {
313 		fsal_status_t status = (*new_obj)->obj_ops.setattr2(*new_obj, false, NULL, attrib);
314 		if (FSAL_IS_ERROR(status)) {
315 			LogFullDebug(COMPONENT_FSAL, "setattr2 status=%s", fsal_err_txt(status));
316 			(*new_obj)->obj_ops.release(*new_obj);
317 			*new_obj = NULL;
318 		}
319 	} else {
320 		if (attrs_out != NULL) {
321 			posix2fsal_attributes_all(&node_entry.attr, attrs_out);
322 		}
323 	}
324 
325 	FSAL_SET_MASK(attrib->valid_mask, ATTR_MODE);
326 
327 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
328 }
329 
330 /*! \brief Read the content of a link
331  *
332  * \see fsal_api.h for more information
333  */
lzfs_fsal_readlink(struct fsal_obj_handle * link_hdl,struct gsh_buffdesc * content_buf,bool refresh)334 static fsal_status_t lzfs_fsal_readlink(struct fsal_obj_handle *link_hdl,
335                                         struct gsh_buffdesc *content_buf, bool refresh) {
336 	struct lzfs_fsal_export *lzfs_export;
337 	struct lzfs_fsal_handle *lzfs_link;
338 	char result[LIZARDFS_MAX_READLINK_LENGTH];
339 	int rc;
340 
341 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
342 	lzfs_link = container_of(link_hdl, struct lzfs_fsal_handle, handle);
343 
344 	LogFullDebug(COMPONENT_FSAL, "export=%" PRIu16 " inode=%" PRIu32, lzfs_export->export.export_id,
345 	             lzfs_link->inode);
346 
347 	rc = liz_cred_readlink(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_link->inode, result,
348 	                       LIZARDFS_MAX_READLINK_LENGTH);
349 	if (rc < 0) {
350 		return lzfs_fsal_last_err();
351 	}
352 
353 	rc = MIN(rc, LIZARDFS_MAX_READLINK_LENGTH);
354 	content_buf->addr = gsh_strldup(result, rc, &content_buf->len);
355 
356 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
357 }
358 
359 /*! \brief Get attributes
360  *
361  * \see fsal_api.h for more information
362  */
lzfs_fsal_getattrs(struct fsal_obj_handle * obj_hdl,struct attrlist * attrs)363 static fsal_status_t lzfs_fsal_getattrs(struct fsal_obj_handle *obj_hdl, struct attrlist *attrs) {
364 	struct lzfs_fsal_export *lzfs_export;
365 	struct lzfs_fsal_handle *lzfs_obj;
366 	struct liz_attr_reply lzfs_attrs;
367 	int rc;
368 
369 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
370 	lzfs_obj = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
371 
372 	LogFullDebug(COMPONENT_FSAL, "export=%" PRIu16 " inode=%" PRIu32, lzfs_export->export.export_id,
373 	             lzfs_obj->inode);
374 
375 	rc = liz_cred_getattr(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_obj->inode, &lzfs_attrs);
376 
377 	if (rc < 0) {
378 		if (attrs->request_mask & ATTR_RDATTR_ERR) {
379 			attrs->valid_mask = ATTR_RDATTR_ERR;
380 		}
381 		LogFullDebug(COMPONENT_FSAL, "getattrs status=%s", liz_error_string(liz_last_err()));
382 		return lzfs_fsal_last_err();
383 	}
384 
385 	posix2fsal_attributes_all(&lzfs_attrs.attr, attrs);
386 	if (attrs->request_mask & ATTR_ACL) {
387 		fsal_status_t status =
388 		    lzfs_int_getacl(lzfs_export, lzfs_obj->inode, lzfs_attrs.attr.st_uid, &attrs->acl);
389 		if (!FSAL_IS_ERROR(status)) {
390 			attrs->valid_mask |= ATTR_ACL;
391 		}
392 	}
393 
394 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
395 }
396 
397 /*! \brief Rename a file
398  *
399  * \see fsal_api.h for more information
400  */
lzfs_fsal_rename(struct fsal_obj_handle * obj_hdl,struct fsal_obj_handle * olddir_hdl,const char * old_name,struct fsal_obj_handle * newdir_hdl,const char * new_name)401 static fsal_status_t lzfs_fsal_rename(struct fsal_obj_handle *obj_hdl,
402                                       struct fsal_obj_handle *olddir_hdl, const char *old_name,
403                                       struct fsal_obj_handle *newdir_hdl, const char *new_name) {
404 	struct lzfs_fsal_export *lzfs_export;
405 	struct lzfs_fsal_handle *lzfs_olddir, *lzfs_newdir;
406 	int rc;
407 
408 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
409 	lzfs_olddir = container_of(olddir_hdl, struct lzfs_fsal_handle, handle);
410 	lzfs_newdir = container_of(newdir_hdl, struct lzfs_fsal_handle, handle);
411 
412 	LogFullDebug(COMPONENT_FSAL, "export=%" PRIu16 " old_inode=%" PRIu32 " new_inode=%" PRIu32
413 	                             " old_name=%s new_name=%s",
414 	             lzfs_export->export.export_id, lzfs_olddir->inode, lzfs_newdir->inode, old_name,
415 	             new_name);
416 
417 	rc = liz_cred_rename(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_olddir->inode, old_name,
418 	                     lzfs_newdir->inode, new_name);
419 
420 	if (rc < 0) {
421 		return lzfs_fsal_last_err();
422 	}
423 
424 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
425 }
426 
427 /*! \brief Remove a name from a directory
428  *
429  * \see fsal_api.h for more information
430  */
lzfs_fsal_unlink(struct fsal_obj_handle * dir_hdl,struct fsal_obj_handle * obj_hdl,const char * name)431 static fsal_status_t lzfs_fsal_unlink(struct fsal_obj_handle *dir_hdl,
432                                       struct fsal_obj_handle *obj_hdl, const char *name) {
433 	struct lzfs_fsal_export *lzfs_export;
434 	struct lzfs_fsal_handle *lzfs_dir;
435 	int rc;
436 
437 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
438 	lzfs_dir = container_of(dir_hdl, struct lzfs_fsal_handle, handle);
439 
440 	LogFullDebug(COMPONENT_FSAL, "export=%" PRIu16 " parent_inode=%" PRIu32 " name=%s type=%s",
441 	             lzfs_export->export.export_id, lzfs_dir->inode, name,
442 	             object_file_type_to_str(obj_hdl->type));
443 
444 	if (obj_hdl->type != DIRECTORY) {
445 		rc = liz_cred_unlink(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_dir->inode, name);
446 	} else {
447 		rc = liz_cred_rmdir(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_dir->inode, name);
448 	}
449 
450 	if (rc < 0) {
451 		return lzfs_fsal_last_err();
452 	}
453 
454 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
455 }
456 
457 /*! \brief Write wire handle
458  *
459  * \see fsal_api.h for more information
460  */
lzfs_fsal_handle_to_wire(const struct fsal_obj_handle * obj_hdl,uint32_t output_type,struct gsh_buffdesc * fh_desc)461 static fsal_status_t lzfs_fsal_handle_to_wire(const struct fsal_obj_handle *obj_hdl,
462                                               uint32_t output_type, struct gsh_buffdesc *fh_desc) {
463 	struct lzfs_fsal_handle *lzfs_obj;
464 
465 	lzfs_obj = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
466 
467 	liz_inode_t inode;
468 	inode = lzfs_obj->inode;
469 
470 	if (fh_desc->len < sizeof(liz_inode_t)) {
471 		LogMajor(COMPONENT_FSAL, "Space too small for handle. Need %zu, have %zu",
472 		         sizeof(liz_inode_t), fh_desc->len);
473 		return fsalstat(ERR_FSAL_TOOSMALL, 0);
474 	}
475 
476 	memcpy(fh_desc->addr, &inode, sizeof(liz_inode_t));
477 	fh_desc->len = sizeof(inode);
478 
479 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
480 }
481 
482 /*! \brief Get key for handle
483  *
484  * \see fsal_api.h for more information
485  */
lzfs_fsal_handle_to_key(struct fsal_obj_handle * obj_hdl,struct gsh_buffdesc * fh_desc)486 static void lzfs_fsal_handle_to_key(struct fsal_obj_handle *obj_hdl, struct gsh_buffdesc *fh_desc) {
487 	struct lzfs_fsal_handle *lzfs_obj;
488 
489 	lzfs_obj = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
490 
491 	fh_desc->addr = &lzfs_obj->unique_key;
492 	fh_desc->len = sizeof(struct lzfs_fsal_key);
493 }
494 
lzfs_int_open_fd(struct lzfs_fsal_handle * lzfs_obj,fsal_openflags_t openflags,struct lzfs_fsal_fd * lzfs_fd,bool no_access_check)495 static fsal_status_t lzfs_int_open_fd(struct lzfs_fsal_handle *lzfs_obj, fsal_openflags_t openflags,
496                                       struct lzfs_fsal_fd *lzfs_fd, bool no_access_check) {
497 	struct lzfs_fsal_export *lzfs_export;
498 	int posix_flags;
499 
500 	fsal2posix_openflags(openflags, &posix_flags);
501 	if (no_access_check) {
502 		posix_flags |= O_CREAT;
503 	}
504 
505 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
506 
507 	LogFullDebug(COMPONENT_FSAL, "fd = %p fd->fd = %p openflags = %x, posix_flags = %x", lzfs_fd,
508 	             lzfs_fd->fd, openflags, posix_flags);
509 
510 	assert(lzfs_fd->fd == NULL && lzfs_fd->openflags == FSAL_O_CLOSED && openflags != 0);
511 
512 	lzfs_fd->fd =
513 	    liz_cred_open(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_obj->inode, posix_flags);
514 
515 	if (!lzfs_fd->fd) {
516 		LogFullDebug(COMPONENT_FSAL, "open failed with %s", liz_error_string(liz_last_err()));
517 		return lzfs_fsal_last_err();
518 	}
519 
520 	LogFullDebug(COMPONENT_FSAL, "fd = %p, new openflags = %x", lzfs_fd->fd, openflags);
521 
522 	lzfs_fd->openflags = openflags;
523 
524 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
525 }
526 
lzfs_int_close_fd(struct lzfs_fsal_handle * lzfs_obj,struct lzfs_fsal_fd * fd)527 static fsal_status_t lzfs_int_close_fd(struct lzfs_fsal_handle *lzfs_obj, struct lzfs_fsal_fd *fd) {
528 	if (fd->fd != NULL && fd->openflags != FSAL_O_CLOSED) {
529 		int rc = liz_release(lzfs_obj->export->lzfs_instance, fd->fd);
530 		fd->fd = NULL;
531 		fd->openflags = FSAL_O_CLOSED;
532 		if (rc < 0) {
533 			return lzfs_fsal_last_err();
534 		}
535 	}
536 
537 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
538 }
539 
lzfs_int_open_by_handle(struct fsal_obj_handle * obj_hdl,struct state_t * state,fsal_openflags_t openflags,enum fsal_create_mode createmode,fsal_verifier_t verifier,struct attrlist * attrs_out,bool * caller_perm_check,bool after_mknod)540 static fsal_status_t lzfs_int_open_by_handle(struct fsal_obj_handle *obj_hdl, struct state_t *state,
541                                              fsal_openflags_t openflags,
542                                              enum fsal_create_mode createmode,
543                                              fsal_verifier_t verifier, struct attrlist *attrs_out,
544                                              bool *caller_perm_check, bool after_mknod) {
545 	struct lzfs_fsal_export *lzfs_export;
546 	struct lzfs_fsal_handle *lzfs_hdl;
547 	struct lzfs_fsal_fd *lzfs_fd;
548 	fsal_status_t status = fsalstat(ERR_FSAL_NO_ERROR, 0);
549 	int posix_flags;
550 
551 	lzfs_hdl = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
552 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
553 
554 	PTHREAD_RWLOCK_wrlock(&obj_hdl->obj_lock);
555 
556 	if (state != NULL) {
557 		lzfs_fd = &container_of(state, struct lzfs_fsal_state_fd, state)->lzfs_fd;
558 
559 		status = check_share_conflict(&lzfs_hdl->share, openflags, false);
560 
561 		if (FSAL_IS_ERROR(status)) {
562 			PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
563 			return status;
564 		}
565 
566 		update_share_counters(&lzfs_hdl->share, FSAL_O_CLOSED, openflags);
567 
568 		PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
569 	} else {
570 		lzfs_fd = &lzfs_hdl->fd;
571 	}
572 
573 	status = lzfs_int_open_fd(lzfs_hdl, openflags, lzfs_fd, after_mknod);
574 
575 	if (FSAL_IS_ERROR(status)) {
576 		if (state != NULL) {
577 			goto undo_share;
578 		}
579 
580 		PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
581 		return status;
582 	}
583 
584 	fsal2posix_openflags(openflags, &posix_flags);
585 	bool truncated = (posix_flags & O_TRUNC) != 0;
586 
587 	if (createmode >= FSAL_EXCLUSIVE || truncated || attrs_out) {
588 		struct liz_attr_reply lzfs_attrs;
589 		int rc;
590 
591 		rc = liz_cred_getattr(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_hdl->inode,
592 		                      &lzfs_attrs);
593 
594 		if (rc == 0) {
595 			LogFullDebug(COMPONENT_FSAL, "New size = %" PRIx64, (int64_t)lzfs_attrs.attr.st_size);
596 		} else {
597 			status = lzfs_fsal_last_err();
598 		}
599 
600 		if (!FSAL_IS_ERROR(status) && createmode >= FSAL_EXCLUSIVE &&
601 		    createmode != FSAL_EXCLUSIVE_9P && !check_verifier_stat(&lzfs_attrs.attr, verifier)) {
602 			// Verifier didn't match, return EEXIST
603 			status = fsalstat(posix2fsal_error(EEXIST), EEXIST);
604 		}
605 
606 		if (!FSAL_IS_ERROR(status) && attrs_out) {
607 			posix2fsal_attributes_all(&lzfs_attrs.attr, attrs_out);
608 		}
609 	}
610 
611 	if (state == NULL) {
612 		PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
613 		// If success, we haven't done any permission check so ask the caller to do so.
614 		*caller_perm_check = !FSAL_IS_ERROR(status);
615 		return status;
616 	}
617 
618 	if (!FSAL_IS_ERROR(status)) {
619 		// Return success. We haven't done any permission check so ask the caller to do so.
620 		*caller_perm_check = true;
621 		return status;
622 	}
623 
624 	lzfs_int_close_fd(lzfs_hdl, lzfs_fd);
625 
626 undo_share:
627 	// On error we need to release our share reservation
628 	// and undo the update of the share counters.
629 	PTHREAD_RWLOCK_wrlock(&obj_hdl->obj_lock);
630 	update_share_counters(&lzfs_hdl->share, openflags, FSAL_O_CLOSED);
631 	PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
632 
633 	return status;
634 }
635 
lzfs_int_open_by_name(struct fsal_obj_handle * obj_hdl,struct state_t * state,fsal_openflags_t openflags,const char * name,fsal_verifier_t verifier,struct attrlist * attrs_out,bool * caller_perm_check)636 static fsal_status_t lzfs_int_open_by_name(struct fsal_obj_handle *obj_hdl, struct state_t *state,
637                                            fsal_openflags_t openflags, const char *name,
638                                            fsal_verifier_t verifier, struct attrlist *attrs_out,
639                                            bool *caller_perm_check) {
640 	struct fsal_obj_handle *temp = NULL;
641 	fsal_status_t status;
642 
643 	status = obj_hdl->obj_ops.lookup(obj_hdl, name, &temp, NULL);
644 
645 	if (FSAL_IS_ERROR(status)) {
646 		LogFullDebug(COMPONENT_FSAL, "lookup returned %s", fsal_err_txt(status));
647 		return status;
648 	}
649 
650 	status = lzfs_int_open_by_handle(temp, state, openflags, FSAL_NO_CREATE, verifier, attrs_out,
651 	                                 caller_perm_check, false);
652 
653 	if (FSAL_IS_ERROR(status)) {
654 		temp->obj_ops.release(temp);
655 		LogFullDebug(COMPONENT_FSAL, "open returned %s", fsal_err_txt(status));
656 	}
657 
658 	return status;
659 }
660 
661 /*! \brief Open a file descriptor for read or write and possibly create
662  *
663  * \see fsal_api.h for more information
664  */
lzfs_fsal_open2(struct fsal_obj_handle * obj_hdl,struct state_t * state,fsal_openflags_t openflags,enum fsal_create_mode createmode,const char * name,struct attrlist * attr_set,fsal_verifier_t verifier,struct fsal_obj_handle ** new_obj,struct attrlist * attrs_out,bool * caller_perm_check)665 static fsal_status_t lzfs_fsal_open2(struct fsal_obj_handle *obj_hdl, struct state_t *state,
666                                      fsal_openflags_t openflags, enum fsal_create_mode createmode,
667                                      const char *name, struct attrlist *attr_set,
668                                      fsal_verifier_t verifier, struct fsal_obj_handle **new_obj,
669                                      struct attrlist *attrs_out, bool *caller_perm_check) {
670 	struct lzfs_fsal_export *lzfs_export;
671 	struct lzfs_fsal_handle *lzfs_obj;
672 	fsal_status_t status = fsalstat(ERR_FSAL_NO_ERROR, 0);
673 	int rc;
674 
675 	LogFullDebug(COMPONENT_FSAL, "name=%s", name);
676 	LogAttrlist(COMPONENT_FSAL, NIV_FULL_DEBUG, "attrs ", attr_set, false);
677 
678 	if (createmode >= FSAL_EXCLUSIVE) {
679 		set_common_verifier(attr_set, verifier);
680 	}
681 
682 	if (name == NULL) {
683 		return lzfs_int_open_by_handle(obj_hdl, state, openflags, createmode, verifier, attrs_out,
684 		                               caller_perm_check, false);
685 	}
686 
687 	if (createmode == FSAL_NO_CREATE) {
688 		return lzfs_int_open_by_name(obj_hdl, state, openflags, name, verifier, attrs_out,
689 		                             caller_perm_check);
690 	}
691 
692 	//
693 	// Create file
694 	//
695 
696 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
697 	lzfs_obj = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
698 
699 	mode_t unix_mode = fsal2unix_mode(attr_set->mode) &
700 	                   ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export);
701 
702 	FSAL_UNSET_MASK(attr_set->valid_mask, ATTR_MODE);
703 
704 	struct liz_entry lzfs_attrs;
705 	rc = liz_cred_mknod(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_obj->inode, name, unix_mode,
706 	                    0, &lzfs_attrs);
707 
708 	if (rc < 0 && liz_last_err() == LIZARDFS_ERROR_EEXIST && createmode == FSAL_UNCHECKED) {
709 		return lzfs_int_open_by_name(obj_hdl, state, openflags, name, verifier, attrs_out,
710 		                             caller_perm_check);
711 	}
712 
713 	if (rc < 0) {
714 		return lzfs_fsal_last_err();
715 	}
716 
717 	// File has been created by us.
718 	*caller_perm_check = false;
719 	struct lzfs_fsal_handle *lzfs_new_obj = lzfs_fsal_new_handle(&lzfs_attrs.attr, lzfs_export);
720 
721 	*new_obj = &lzfs_new_obj->handle;
722 
723 	if (attr_set->valid_mask != 0) {
724 		status = (*new_obj)->obj_ops.setattr2(*new_obj, false, state, attr_set);
725 		if (FSAL_IS_ERROR(status)) {
726 			goto fileerr;
727 		}
728 
729 		if (attrs_out != NULL) {
730 			status = (*new_obj)->obj_ops.getattrs(*new_obj, attrs_out);
731 			if (FSAL_IS_ERROR(status) && (attrs_out->request_mask & ATTR_RDATTR_ERR) == 0) {
732 				goto fileerr;
733 			}
734 
735 			attrs_out = NULL;
736 		}
737 	}
738 
739 	if (attrs_out != NULL) {
740 		posix2fsal_attributes_all(&lzfs_attrs.attr, attrs_out);
741 	}
742 
743 	return lzfs_int_open_by_handle(*new_obj, state, openflags, createmode, verifier, NULL,
744 	                               caller_perm_check, true);
745 
746 fileerr:
747 	(*new_obj)->obj_ops.release(*new_obj);
748 	*new_obj = NULL;
749 
750 	rc = liz_cred_unlink(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_obj->inode, name);
751 
752 	return status;
753 }
754 
755 /*! \brief Return open status of a state.
756  *
757  * \see fsal_api.h for more information
758  */
lzfs_fsal_status2(struct fsal_obj_handle * obj_hdl,struct state_t * state)759 static fsal_openflags_t lzfs_fsal_status2(struct fsal_obj_handle *obj_hdl, struct state_t *state) {
760 	struct lzfs_fsal_fd *lzfs_fd;
761 	lzfs_fd = &container_of(state, struct lzfs_fsal_state_fd, state)->lzfs_fd;
762 	return lzfs_fd->openflags;
763 }
764 
765 /*! \brief Re-open a file that may be already opened
766  *
767  * \see fsal_api.h for more information
768  */
lzfs_fsal_reopen2(struct fsal_obj_handle * obj_hdl,struct state_t * state,fsal_openflags_t openflags)769 static fsal_status_t lzfs_fsal_reopen2(struct fsal_obj_handle *obj_hdl, struct state_t *state,
770                                        fsal_openflags_t openflags) {
771 	struct lzfs_fsal_handle *lzfs_hdl;
772 	struct lzfs_fsal_fd fd, *lzfs_share_fd;
773 	fsal_status_t status;
774 	fsal_openflags_t old_openflags;
775 
776 	lzfs_hdl = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
777 	lzfs_share_fd = &container_of(state, struct lzfs_fsal_state_fd, state)->lzfs_fd;
778 
779 	LogFullDebug(COMPONENT_FSAL, "export=%" PRIu16 " inode=%" PRIu32,
780 	             lzfs_hdl->unique_key.export_id, lzfs_hdl->inode);
781 
782 	memset(&fd, 0, sizeof(fd));
783 
784 	PTHREAD_RWLOCK_wrlock(&obj_hdl->obj_lock);
785 
786 	old_openflags = lzfs_share_fd->openflags;
787 
788 	status = check_share_conflict(&lzfs_hdl->share, openflags, false);
789 
790 	if (FSAL_IS_ERROR(status)) {
791 		PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
792 		return status;
793 	}
794 
795 	update_share_counters(&lzfs_hdl->share, old_openflags, openflags);
796 
797 	PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
798 
799 	status = lzfs_int_open_fd(lzfs_hdl, openflags, &fd, true);
800 
801 	if (!FSAL_IS_ERROR(status)) {
802 		lzfs_int_close_fd(lzfs_hdl, lzfs_share_fd);
803 		*lzfs_share_fd = fd;
804 	} else {
805 		PTHREAD_RWLOCK_wrlock(&obj_hdl->obj_lock);
806 		update_share_counters(&lzfs_hdl->share, openflags, old_openflags);
807 		PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
808 	}
809 
810 	return status;
811 }
812 
lzfs_int_open_func(struct fsal_obj_handle * obj_hdl,fsal_openflags_t openflags,struct fsal_fd * fd)813 static fsal_status_t lzfs_int_open_func(struct fsal_obj_handle *obj_hdl, fsal_openflags_t openflags,
814                                         struct fsal_fd *fd) {
815 	struct lzfs_fsal_handle *lzfs_hdl;
816 	lzfs_hdl = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
817 	return lzfs_int_open_fd(lzfs_hdl, openflags, (struct lzfs_fsal_fd *)fd, true);
818 }
819 
lzfs_int_close_func(struct fsal_obj_handle * obj_hdl,struct fsal_fd * fd)820 static fsal_status_t lzfs_int_close_func(struct fsal_obj_handle *obj_hdl, struct fsal_fd *fd) {
821 	struct lzfs_fsal_handle *lzfs_hdl;
822 	lzfs_hdl = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
823 	return lzfs_int_close_fd(lzfs_hdl, (struct lzfs_fsal_fd *)fd);
824 }
825 
lzfs_int_find_fd(struct lzfs_fsal_fd * fd,struct fsal_obj_handle * obj_hdl,bool bypass,struct state_t * state,fsal_openflags_t openflags,bool * has_lock,bool * closefd,bool open_for_locks)826 static fsal_status_t lzfs_int_find_fd(struct lzfs_fsal_fd *fd, struct fsal_obj_handle *obj_hdl,
827                                       bool bypass, struct state_t *state,
828                                       fsal_openflags_t openflags, bool *has_lock, bool *closefd,
829                                       bool open_for_locks) {
830 	struct lzfs_fsal_handle *lzfs_hdl = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
831 	struct lzfs_fsal_fd temp_fd = {0, NULL}, *out_fd = &temp_fd;
832 	fsal_status_t status;
833 
834 	status = fsal_find_fd((struct fsal_fd **)&out_fd, obj_hdl, (struct fsal_fd *)&lzfs_hdl->fd,
835 	                      &lzfs_hdl->share, bypass, state, openflags, lzfs_int_open_func,
836 	                      lzfs_int_close_func, has_lock, closefd, open_for_locks);
837 	*fd = *out_fd;
838 	return status;
839 }
840 
841 /**
842  * \brief Read data from a file
843  *
844  * \see fsal_api.h for more information
845  */
lzfs_fsal_read2(struct fsal_obj_handle * obj_hdl,bool bypass,struct state_t * state,uint64_t offset,size_t buffer_size,void * buffer,size_t * read_amount,bool * end_of_file,struct io_info * info)846 static fsal_status_t lzfs_fsal_read2(struct fsal_obj_handle *obj_hdl, bool bypass,
847                                      struct state_t *state, uint64_t offset, size_t buffer_size,
848                                      void *buffer, size_t *read_amount, bool *end_of_file,
849                                      struct io_info *info) {
850 	struct lzfs_fsal_export *lzfs_export;
851 	struct lzfs_fsal_handle *lzfs_obj;
852 	struct lzfs_fsal_fd lzfs_fd;
853 	fsal_status_t status = fsalstat(ERR_FSAL_NO_ERROR, 0);
854 	bool has_lock = false;
855 	bool closefd = false;
856 	ssize_t nb_read;
857 
858 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
859 	lzfs_obj = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
860 
861 	LogFullDebug(COMPONENT_FSAL, "export=%" PRIu16 " inode=%" PRIu32 " offset=%" PRIu64 " size=%zu",
862 	             lzfs_export->export.export_id, lzfs_obj->inode, offset, buffer_size);
863 
864 	if (info != NULL) {
865 		return fsalstat(ERR_FSAL_NOTSUPP, 0);
866 	}
867 
868 	status =
869 	    lzfs_int_find_fd(&lzfs_fd, obj_hdl, bypass, state, FSAL_O_READ, &has_lock, &closefd, false);
870 
871 	if (FSAL_IS_ERROR(status)) {
872 		return status;
873 	}
874 
875 	nb_read = liz_cred_read(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_fd.fd, offset,
876 	                        buffer_size, buffer);
877 
878 	if (offset == -1 || nb_read < 0) {
879 		status = lzfs_fsal_last_err();
880 	} else {
881 		*read_amount = nb_read;
882 		*end_of_file = (nb_read == 0);
883 	}
884 
885 	if (closefd) {
886 		lzfs_int_close_fd(lzfs_obj, &lzfs_fd);
887 	}
888 
889 	if (has_lock) {
890 		PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
891 	}
892 
893 	return status;
894 }
895 
896 /*! \brief Write data to a file
897  *
898  * \see fsal_api.h for more information
899  */
lzfs_fsal_write2(struct fsal_obj_handle * obj_hdl,bool bypass,struct state_t * state,uint64_t offset,size_t buffer_size,void * buffer,size_t * wrote_amount,bool * fsal_stable,struct io_info * info)900 static fsal_status_t lzfs_fsal_write2(struct fsal_obj_handle *obj_hdl, bool bypass,
901                                       struct state_t *state, uint64_t offset, size_t buffer_size,
902                                       void *buffer, size_t *wrote_amount, bool *fsal_stable,
903                                       struct io_info *info) {
904 	struct lzfs_fsal_export *lzfs_export;
905 	struct lzfs_fsal_handle *lzfs_obj;
906 	struct lzfs_fsal_fd lzfs_fd;
907 	fsal_status_t status = fsalstat(ERR_FSAL_NO_ERROR, 0);
908 	bool has_lock = false;
909 	bool closefd = false;
910 	ssize_t nb_written;
911 
912 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
913 	lzfs_obj = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
914 
915 	LogFullDebug(COMPONENT_FSAL, "export=%" PRIu16 " inode=%" PRIu32 " offset=%" PRIu64 " size=%zu",
916 	             lzfs_export->export.export_id, lzfs_obj->inode, offset, buffer_size);
917 
918 	if (info != NULL) {
919 		return fsalstat(ERR_FSAL_NOTSUPP, 0);
920 	}
921 
922 	status = lzfs_int_find_fd(&lzfs_fd, obj_hdl, bypass, state, FSAL_O_WRITE, &has_lock, &closefd,
923 	                          false);
924 
925 	if (FSAL_IS_ERROR(status)) {
926 		return status;
927 	}
928 
929 	nb_written = liz_cred_write(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_fd.fd, offset,
930 	                            buffer_size, buffer);
931 
932 	if (nb_written < 0) {
933 		status = lzfs_fsal_last_err();
934 	} else {
935 		*wrote_amount = nb_written;
936 		if (*fsal_stable) {
937 			int rc = liz_cred_fsync(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_fd.fd);
938 
939 			if (rc < 0) {
940 				status = lzfs_fsal_last_err();
941 			}
942 		}
943 	}
944 
945 	if (closefd) {
946 		lzfs_int_close_fd(lzfs_obj, &lzfs_fd);
947 	}
948 
949 	if (has_lock) {
950 		PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
951 	}
952 
953 	return status;
954 }
955 
956 /*! \brief Commit written data
957  *
958  * \see fsal_api.h for more information
959  */
lzfs_fsal_commit2(struct fsal_obj_handle * obj_hdl,off_t offset,size_t len)960 static fsal_status_t lzfs_fsal_commit2(struct fsal_obj_handle *obj_hdl, off_t offset, size_t len) {
961 	struct lzfs_fsal_export *lzfs_export;
962 	struct lzfs_fsal_handle *lzfs_obj;
963 	struct lzfs_fsal_fd temp_fd = {0, NULL}, *out_fd = &temp_fd;
964 	fsal_status_t status;
965 	bool has_lock = false;
966 	bool closefd = false;
967 
968 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
969 	lzfs_obj = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
970 
971 	LogFullDebug(COMPONENT_FSAL, "export=%" PRIu16 " inode=%" PRIu32 " offset=%lli len=%zu",
972 	             lzfs_export->export.export_id, lzfs_obj->inode, (long long)offset, len);
973 
974 	status = fsal_reopen_obj(obj_hdl, false, false, FSAL_O_WRITE, (struct fsal_fd *)&lzfs_obj->fd,
975 	                         &lzfs_obj->share, lzfs_int_open_func, lzfs_int_close_func,
976 	                         (struct fsal_fd **)&out_fd, &has_lock, &closefd);
977 
978 	if (!FSAL_IS_ERROR(status)) {
979 		int rc = liz_cred_fsync(lzfs_export->lzfs_instance, op_ctx->creds, out_fd->fd);
980 
981 		if (rc < 0) {
982 			status = lzfs_fsal_last_err();
983 		}
984 	}
985 
986 	if (closefd) {
987 		int rc = liz_release(lzfs_export->lzfs_instance, out_fd->fd);
988 		if (rc < 0) {
989 			status = lzfs_fsal_last_err();
990 		}
991 	}
992 
993 	if (has_lock) {
994 		PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
995 	}
996 
997 	return status;
998 }
999 
1000 /*! \brief Close a file
1001  *
1002  * \see fsal_api.h for more information
1003  */
lzfs_fsal_close(struct fsal_obj_handle * obj_hdl)1004 static fsal_status_t lzfs_fsal_close(struct fsal_obj_handle *obj_hdl) {
1005 	struct lzfs_fsal_handle *lzfs_obj;
1006 	fsal_status_t status;
1007 
1008 	lzfs_obj = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
1009 
1010 	LogFullDebug(COMPONENT_FSAL, "export=%" PRIu16 " inode=%" PRIu32,
1011 	             lzfs_obj->unique_key.export_id, lzfs_obj->inode);
1012 
1013 	PTHREAD_RWLOCK_wrlock(&obj_hdl->obj_lock);
1014 
1015 	status = lzfs_int_close_fd(lzfs_obj, &lzfs_obj->fd);
1016 
1017 	PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
1018 
1019 	return status;
1020 }
1021 
1022 /*! \brief Merge a duplicate handle with an original handle
1023  *
1024  * \see fsal_api.h for more information
1025  */
lzfs_fsal_merge(struct fsal_obj_handle * orig_hdl,struct fsal_obj_handle * dupe_hdl)1026 static fsal_status_t lzfs_fsal_merge(struct fsal_obj_handle *orig_hdl,
1027                                      struct fsal_obj_handle *dupe_hdl) {
1028 	fsal_status_t status = fsalstat(ERR_FSAL_NO_ERROR, 0);
1029 
1030 	if (orig_hdl->type == REGULAR_FILE && dupe_hdl->type == REGULAR_FILE) {
1031 		struct lzfs_fsal_handle *lzfs_orig, *lzfs_dupe;
1032 
1033 		lzfs_orig = container_of(orig_hdl, struct lzfs_fsal_handle, handle);
1034 		lzfs_dupe = container_of(dupe_hdl, struct lzfs_fsal_handle, handle);
1035 
1036 		LogFullDebug(COMPONENT_FSAL,
1037 		             "export=%" PRIu32 " orig_inode=%" PRIu16 " dupe_inode=%" PRIu32,
1038 		             lzfs_orig->unique_key.export_id, lzfs_orig->inode, lzfs_dupe->inode);
1039 
1040 		PTHREAD_RWLOCK_wrlock(&orig_hdl->obj_lock);
1041 
1042 		status = merge_share(&lzfs_orig->share, &lzfs_dupe->share);
1043 
1044 		PTHREAD_RWLOCK_unlock(&orig_hdl->obj_lock);
1045 	}
1046 
1047 	return status;
1048 }
1049 
1050 /*! \brief Set attributes on an object
1051  *
1052  * \see fsal_api.h for more information
1053  */
lzfs_fsal_setattr2(struct fsal_obj_handle * obj_hdl,bool bypass,struct state_t * state,struct attrlist * attrib_set)1054 static fsal_status_t lzfs_fsal_setattr2(struct fsal_obj_handle *obj_hdl, bool bypass,
1055                                         struct state_t *state, struct attrlist *attrib_set) {
1056 	struct lzfs_fsal_export *lzfs_export;
1057 	struct lzfs_fsal_handle *lzfs_obj;
1058 	bool has_lock = false;
1059 	bool closefd = false;
1060 	fsal_status_t status = fsalstat(ERR_FSAL_NO_ERROR, 0);
1061 
1062 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
1063 	lzfs_obj = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
1064 
1065 	LogAttrlist(COMPONENT_FSAL, NIV_FULL_DEBUG, "attrs ", attrib_set, false);
1066 
1067 	if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_MODE)) {
1068 		attrib_set->mode &= ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export);
1069 	}
1070 
1071 	if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_SIZE)) {
1072 		if (obj_hdl->type != REGULAR_FILE) {
1073 			LogFullDebug(COMPONENT_FSAL, "Setting size on non-regular file");
1074 			return fsalstat(ERR_FSAL_INVAL, EINVAL);
1075 		}
1076 
1077 		status = fsal_find_fd(NULL, obj_hdl, NULL, &lzfs_obj->share, bypass, state, FSAL_O_RDWR,
1078 		                      NULL, NULL, &has_lock, &closefd, false);
1079 
1080 		if (FSAL_IS_ERROR(status)) {
1081 			LogFullDebug(COMPONENT_FSAL, "fsal_find_fd status=%s", fsal_err_txt(status));
1082 			goto out;
1083 		}
1084 	}
1085 
1086 	struct stat attr;
1087 	int mask = 0;
1088 
1089 	memset(&attr, 0, sizeof(attr));
1090 
1091 	if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_SIZE)) {
1092 		mask |= LIZ_SET_ATTR_SIZE;
1093 		attr.st_size = attrib_set->filesize;
1094 		LogFullDebug(COMPONENT_FSAL, "setting size to %lld", (long long)attr.st_size);
1095 	}
1096 
1097 	if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_MODE)) {
1098 		mask |= LIZ_SET_ATTR_MODE;
1099 		attr.st_mode = fsal2unix_mode(attrib_set->mode);
1100 	}
1101 
1102 	if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_OWNER)) {
1103 		mask |= LIZ_SET_ATTR_UID;
1104 		attr.st_uid = attrib_set->owner;
1105 	}
1106 
1107 	if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_GROUP)) {
1108 		mask |= LIZ_SET_ATTR_GID;
1109 		attr.st_gid = attrib_set->group;
1110 	}
1111 
1112 	if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_ATIME)) {
1113 		mask |= LIZ_SET_ATTR_ATIME;
1114 		attr.st_atim = attrib_set->atime;
1115 	}
1116 
1117 	if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_ATIME_SERVER)) {
1118 		mask |= LIZ_SET_ATTR_ATIME_NOW;
1119 	}
1120 
1121 	if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_MTIME)) {
1122 		mask |= LIZ_SET_ATTR_MTIME;
1123 		attr.st_mtim = attrib_set->mtime;
1124 	}
1125 
1126 	if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_MTIME_SERVER)) {
1127 		mask |= LIZ_SET_ATTR_MTIME_NOW;
1128 	}
1129 
1130 	liz_attr_reply_t reply;
1131 	int rc = liz_cred_setattr(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_obj->inode, &attr,
1132 	                          mask, &reply);
1133 
1134 	if (rc < 0) {
1135 		LogFullDebug(COMPONENT_FSAL, "liz_setattr returned %s (%d)",
1136 		             liz_error_string(liz_last_err()), liz_last_err());
1137 		status = lzfs_fsal_last_err();
1138 		goto out;
1139 	}
1140 
1141 	if (FSAL_TEST_MASK(attrib_set->valid_mask, ATTR_ACL)) {
1142 		status = lzfs_int_setacl(lzfs_export, lzfs_obj->inode, attrib_set->acl);
1143 	}
1144 
1145 out:
1146 	if (has_lock) {
1147 		PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
1148 	}
1149 
1150 	return status;
1151 }
1152 
1153 /*! \brief Manage closing a file when a state is no longer needed.
1154  *
1155  * \see fsal_api.h for more information
1156  */
lzfs_fsal_close2(struct fsal_obj_handle * obj_hdl,struct state_t * state)1157 static fsal_status_t lzfs_fsal_close2(struct fsal_obj_handle *obj_hdl, struct state_t *state) {
1158 	struct lzfs_fsal_handle *lzfs_obj;
1159 
1160 	lzfs_obj = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
1161 
1162 	LogFullDebug(COMPONENT_FSAL, "export=%" PRIu16 " inode=%" PRIu32,
1163 	             lzfs_obj->unique_key.export_id, lzfs_obj->inode);
1164 
1165 	if (state->state_type == STATE_TYPE_SHARE || state->state_type == STATE_TYPE_NLM_SHARE ||
1166 	    state->state_type == STATE_TYPE_9P_FID) {
1167 		PTHREAD_RWLOCK_wrlock(&obj_hdl->obj_lock);
1168 
1169 		update_share_counters(&lzfs_obj->share, lzfs_obj->fd.openflags, FSAL_O_CLOSED);
1170 
1171 		PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
1172 	}
1173 
1174 	return lzfs_int_close_fd(lzfs_obj, &lzfs_obj->fd);
1175 }
1176 
lzfs_fsal_lock_op2(struct fsal_obj_handle * obj_hdl,struct state_t * state,void * owner,fsal_lock_op_t lock_op,fsal_lock_param_t * request_lock,fsal_lock_param_t * conflicting_lock)1177 fsal_status_t lzfs_fsal_lock_op2(struct fsal_obj_handle *obj_hdl, struct state_t *state,
1178                                  void *owner, fsal_lock_op_t lock_op,
1179                                  fsal_lock_param_t *request_lock,
1180                                  fsal_lock_param_t *conflicting_lock) {
1181 	struct lzfs_fsal_export *lzfs_export;
1182 
1183 	liz_err_t last_err;
1184 	liz_fileinfo_t *fileinfo;
1185 	liz_lock_info_t lock_info;
1186 	fsal_status_t status = {0, 0};
1187 	int retval = 0;
1188 	struct lzfs_fsal_fd liz_fd;
1189 	bool has_lock = false;
1190 	bool closefd = false;
1191 	bool bypass = false;
1192 	fsal_openflags_t openflags = FSAL_O_RDWR;
1193 
1194 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
1195 
1196 	LogFullDebug(COMPONENT_FSAL, "op:%d type:%d start:%" PRIu64 " length:%" PRIu64 " ", lock_op,
1197 	             request_lock->lock_type, request_lock->lock_start, request_lock->lock_length);
1198 
1199 	if (lock_op == FSAL_OP_LOCKT) {
1200 		// We may end up using global fd, don't fail on a deny mode
1201 		bypass = true;
1202 		openflags = FSAL_O_ANY;
1203 	} else if (lock_op == FSAL_OP_LOCK) {
1204 		if (request_lock->lock_type == FSAL_LOCK_R) {
1205 			openflags = FSAL_O_READ;
1206 		} else if (request_lock->lock_type == FSAL_LOCK_W) {
1207 			openflags = FSAL_O_WRITE;
1208 		}
1209 	} else if (lock_op == FSAL_OP_UNLOCK) {
1210 		openflags = FSAL_O_ANY;
1211 	} else {
1212 		LogFullDebug(COMPONENT_FSAL,
1213 		             "ERROR: Lock operation requested was not TEST, READ, or WRITE.");
1214 		return fsalstat(ERR_FSAL_NOTSUPP, 0);
1215 	}
1216 
1217 	if (lock_op != FSAL_OP_LOCKT && state == NULL) {
1218 		LogCrit(COMPONENT_FSAL, "Non TEST operation with NULL state");
1219 		return posix2fsal_status(EINVAL);
1220 	}
1221 
1222 	if (request_lock->lock_type == FSAL_LOCK_R) {
1223 		lock_info.l_type = F_RDLCK;
1224 	} else if (request_lock->lock_type == FSAL_LOCK_W) {
1225 		lock_info.l_type = F_WRLCK;
1226 	} else {
1227 		LogFullDebug(COMPONENT_FSAL, "ERROR: The requested lock type was not read or write.");
1228 		return fsalstat(ERR_FSAL_NOTSUPP, 0);
1229 	}
1230 
1231 	if (lock_op == FSAL_OP_UNLOCK) {
1232 		lock_info.l_type = F_UNLCK;
1233 	}
1234 
1235 	lock_info.l_pid = 0;
1236 	lock_info.l_len = request_lock->lock_length;
1237 	lock_info.l_start = request_lock->lock_start;
1238 
1239 	status =
1240 	    lzfs_int_find_fd(&liz_fd, obj_hdl, bypass, state, openflags, &has_lock, &closefd, true);
1241 	// IF lzfs_int_find_fd returned DELAY, then fd caching in mdcache is turned off, which means
1242 	// that the consecutive attempt is very likely to succeed immediately.
1243 	if (status.major == ERR_FSAL_DELAY) {
1244 		status =
1245 		    lzfs_int_find_fd(&liz_fd, obj_hdl, bypass, state, openflags, &has_lock, &closefd, true);
1246 	}
1247 	if (FSAL_IS_ERROR(status)) {
1248 		LogCrit(COMPONENT_FSAL, "Unable to find fd for lock operation");
1249 		return status;
1250 	}
1251 
1252 	fileinfo = liz_fd.fd;
1253 	liz_set_lock_owner(fileinfo, (uint64_t)owner);
1254 	if (lock_op == FSAL_OP_LOCKT) {
1255 		retval = liz_cred_getlk(lzfs_export->lzfs_instance, op_ctx->creds, fileinfo, &lock_info);
1256 	} else {
1257 		retval = liz_cred_setlk(lzfs_export->lzfs_instance, op_ctx->creds, fileinfo, &lock_info);
1258 	}
1259 
1260 	if (retval < 0) {
1261 		goto err;
1262 	}
1263 
1264 	/* F_UNLCK is returned then the tested operation would be possible. */
1265 	if (conflicting_lock != NULL) {
1266 		if (lock_op == FSAL_OP_LOCKT && lock_info.l_type != F_UNLCK) {
1267 			conflicting_lock->lock_length = lock_info.l_len;
1268 			conflicting_lock->lock_start = lock_info.l_start;
1269 			conflicting_lock->lock_type = lock_info.l_type;
1270 		} else {
1271 			conflicting_lock->lock_length = 0;
1272 			conflicting_lock->lock_start = 0;
1273 			conflicting_lock->lock_type = FSAL_NO_LOCK;
1274 		}
1275 	}
1276 
1277 err:
1278 	last_err = liz_last_err();
1279 	if (closefd) {
1280 		liz_release(lzfs_export->lzfs_instance, fileinfo);
1281 	}
1282 
1283 	if (has_lock) {
1284 		PTHREAD_RWLOCK_unlock(&obj_hdl->obj_lock);
1285 	}
1286 
1287 	if (retval < 0) {
1288 		LogFullDebug(COMPONENT_FSAL, "Returning error %d", last_err);
1289 		return lizardfs2fsal_error(last_err);
1290 	}
1291 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
1292 }
1293 
1294 /*! \brief Create a new link
1295  *
1296  * \see fsal_api.h for more information
1297  */
lzfs_fsal_link(struct fsal_obj_handle * obj_hdl,struct fsal_obj_handle * destdir_hdl,const char * name)1298 static fsal_status_t lzfs_fsal_link(struct fsal_obj_handle *obj_hdl,
1299                                     struct fsal_obj_handle *destdir_hdl, const char *name) {
1300 	struct lzfs_fsal_export *lzfs_export;
1301 	struct lzfs_fsal_handle *lzfs_obj, *lzfs_destdir;
1302 
1303 	lzfs_export = container_of(op_ctx->fsal_export, struct lzfs_fsal_export, export);
1304 	lzfs_obj = container_of(obj_hdl, struct lzfs_fsal_handle, handle);
1305 	lzfs_destdir = container_of(destdir_hdl, struct lzfs_fsal_handle, handle);
1306 
1307 	LogFullDebug(COMPONENT_FSAL,
1308 	             "export=%" PRIu16 " inode=%" PRIu32 " dest_inode=%" PRIu32 " name=%s",
1309 	             lzfs_export->export.export_id, lzfs_obj->inode, lzfs_destdir->inode, name);
1310 
1311 	liz_entry_t result;
1312 	int rc = liz_cred_link(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_obj->inode,
1313 	                       lzfs_destdir->inode, name, &result);
1314 	if (rc < 0) {
1315 		return lzfs_fsal_last_err();
1316 	}
1317 
1318 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
1319 }
1320 
lzfs_fsal_handle_ops_init(struct lzfs_fsal_export * lzfs_export,struct fsal_obj_ops * ops)1321 void lzfs_fsal_handle_ops_init(struct lzfs_fsal_export *lzfs_export, struct fsal_obj_ops *ops) {
1322 	ops->release = lzfs_fsal_release;
1323 	ops->merge = lzfs_fsal_merge;
1324 	ops->lookup = lzfs_fsal_lookup;
1325 	ops->mkdir = lzfs_fsal_mkdir;
1326 	ops->mknode = lzfs_fsal_mknode;
1327 	ops->readdir = lzfs_fsal_readdir;
1328 	ops->symlink = lzfs_fsal_symlink;
1329 	ops->readlink = lzfs_fsal_readlink;
1330 	ops->getattrs = lzfs_fsal_getattrs;
1331 	ops->link = lzfs_fsal_link;
1332 	ops->rename = lzfs_fsal_rename;
1333 	ops->unlink = lzfs_fsal_unlink;
1334 	ops->close = lzfs_fsal_close;
1335 	ops->handle_to_wire = lzfs_fsal_handle_to_wire;
1336 	ops->handle_to_key = lzfs_fsal_handle_to_key;
1337 	ops->open2 = lzfs_fsal_open2;
1338 	ops->status2 = lzfs_fsal_status2;
1339 	ops->reopen2 = lzfs_fsal_reopen2;
1340 	ops->read2 = lzfs_fsal_read2;
1341 	ops->write2 = lzfs_fsal_write2;
1342 	ops->commit2 = lzfs_fsal_commit2;
1343 	ops->setattr2 = lzfs_fsal_setattr2;
1344 	ops->close2 = lzfs_fsal_close2;
1345 	ops->lock_op2 = lzfs_fsal_lock_op2;
1346 
1347 	if (lzfs_export->pnfs_mds_enabled) {
1348 		lzfs_fsal_handle_ops_pnfs(ops);
1349 	}
1350 }
1351