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