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 "fsal.h"
20 #include "fsal_api.h"
21 #include "fsal_types.h"
22 #include "fsal_up.h"
23 #include "FSAL/fsal_commonlib.h"
24 #include "pnfs_utils.h"
25
26 #include "context_wrap.h"
27 #include "lzfs_internal.h"
28 #include "protocol/MFSCommunication.h"
29
30 /*! \brief Grant a layout segment.
31 *
32 * \see fsal_api.h for more information
33 */
lzfs_fsal_layoutget(struct fsal_obj_handle * obj_pub,struct req_op_context * req_ctx,XDR * loc_body,const struct fsal_layoutget_arg * arg,struct fsal_layoutget_res * res)34 static nfsstat4 lzfs_fsal_layoutget(struct fsal_obj_handle *obj_pub, struct req_op_context *req_ctx,
35 XDR *loc_body, const struct fsal_layoutget_arg *arg,
36 struct fsal_layoutget_res *res) {
37 struct lzfs_fsal_handle *lzfs_hdl;
38 struct lzfs_fsal_ds_wire ds_wire;
39 struct gsh_buffdesc ds_desc = {.addr = &ds_wire, .len = sizeof(struct lzfs_fsal_ds_wire)};
40 struct pnfs_deviceid deviceid = DEVICE_ID_INIT_ZERO(FSAL_ID_EXPERIMENTAL);
41 nfl_util4 layout_util = 0;
42 nfsstat4 nfs_status = NFS4_OK;
43
44 lzfs_hdl = container_of(obj_pub, struct lzfs_fsal_handle, handle);
45
46 if (arg->type != LAYOUT4_NFSV4_1_FILES) {
47 LogMajor(COMPONENT_PNFS, "Unsupported layout type: %x", arg->type);
48
49 return NFS4ERR_UNKNOWN_LAYOUTTYPE;
50 }
51
52 LogDebug(COMPONENT_PNFS, "will issue layout offset: %" PRIu64 " length: %" PRIu64,
53 res->segment.offset, res->segment.length);
54
55 deviceid.device_id2 = lzfs_hdl->export->export.export_id;
56 deviceid.devid = lzfs_hdl->inode;
57 ds_wire.inode = lzfs_hdl->inode;
58 layout_util = MFSCHUNKSIZE;
59
60 nfs_status = FSAL_encode_file_layout(loc_body, &deviceid, layout_util, 0, 0,
61 &req_ctx->ctx_export->export_id, 1, &ds_desc);
62 if (nfs_status) {
63 LogMajor(COMPONENT_PNFS, "Failed to encode nfsv4_1_file_layout.");
64 return nfs_status;
65 }
66
67 res->return_on_close = true;
68 res->last_segment = true;
69
70 return nfs_status;
71 }
72
73 /*! \brief Potentially return one layout segment
74 *
75 * \see fsal_api.h for more information
76 */
lzfs_fsal_layoutreturn(struct fsal_obj_handle * obj_pub,struct req_op_context * req_ctx,XDR * lrf_body,const struct fsal_layoutreturn_arg * arg)77 static nfsstat4 lzfs_fsal_layoutreturn(struct fsal_obj_handle *obj_pub,
78 struct req_op_context *req_ctx, XDR *lrf_body,
79 const struct fsal_layoutreturn_arg *arg) {
80 if (arg->lo_type != LAYOUT4_NFSV4_1_FILES) {
81 LogDebug(COMPONENT_PNFS, "Unsupported layout type: %x", arg->lo_type);
82 return NFS4ERR_UNKNOWN_LAYOUTTYPE;
83 }
84
85 return NFS4_OK;
86 }
87
88 /*! \brief Commit a segment of a layout
89 *
90 * \see fsal_api.h for more information
91 */
lzfs_fsal_layoutcommit(struct fsal_obj_handle * obj_pub,struct req_op_context * req_ctx,XDR * lou_body,const struct fsal_layoutcommit_arg * arg,struct fsal_layoutcommit_res * res)92 static nfsstat4 lzfs_fsal_layoutcommit(struct fsal_obj_handle *obj_pub,
93 struct req_op_context *req_ctx, XDR *lou_body,
94 const struct fsal_layoutcommit_arg *arg,
95 struct fsal_layoutcommit_res *res) {
96 struct lzfs_fsal_export *lzfs_export;
97 struct lzfs_fsal_handle *lzfs_hdl;
98 struct liz_attr_reply lzfs_old;
99 int rc;
100
101 // FIXME(haze): Does this function make sense for our implementation ?
102
103 /* Sanity check on type */
104 if (arg->type != LAYOUT4_NFSV4_1_FILES) {
105 LogCrit(COMPONENT_PNFS, "Unsupported layout type: %x", arg->type);
106 return NFS4ERR_UNKNOWN_LAYOUTTYPE;
107 }
108
109 lzfs_export = container_of(req_ctx->fsal_export, struct lzfs_fsal_export, export);
110 lzfs_hdl = container_of(obj_pub, struct lzfs_fsal_handle, handle);
111
112 rc = liz_cred_getattr(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_hdl->inode, &lzfs_old);
113 if (rc < 0) {
114 LogCrit(COMPONENT_PNFS, "Error '%s' in attempt to get attributes of file %lli.",
115 liz_error_string(liz_last_err()), (long long)lzfs_hdl->inode);
116 return lzfs_nfs4_last_err();
117 }
118
119 struct stat attr;
120 int mask = 0;
121
122 memset(&attr, 0, sizeof(attr));
123
124 if (arg->new_offset && lzfs_old.attr.st_size < arg->last_write + 1) {
125 mask |= LIZ_SET_ATTR_SIZE;
126 attr.st_size = arg->last_write + 1;
127 res->size_supplied = true;
128 res->new_size = arg->last_write + 1;
129 }
130
131 if (arg->time_changed && (arg->new_time.seconds > lzfs_old.attr.st_mtim.tv_sec ||
132 (arg->new_time.seconds == lzfs_old.attr.st_mtim.tv_sec &&
133 arg->new_time.nseconds > lzfs_old.attr.st_mtim.tv_nsec))) {
134 attr.st_mtim.tv_sec = arg->new_time.seconds;
135 attr.st_mtim.tv_sec = arg->new_time.nseconds;
136 mask |= LIZ_SET_ATTR_MTIME;
137 }
138
139 liz_attr_reply_t reply;
140 rc = liz_cred_setattr(lzfs_export->lzfs_instance, op_ctx->creds, lzfs_hdl->inode, &attr, mask,
141 &reply);
142
143 if (rc < 0) {
144 LogCrit(COMPONENT_PNFS, "Error '%s' in attempt to set attributes of file %lli.",
145 liz_error_string(liz_last_err()), (long long)lzfs_hdl->inode);
146 return lzfs_nfs4_last_err();
147 }
148
149 res->commit_done = true;
150
151 return NFS4_OK;
152 }
153
lzfs_fsal_handle_ops_pnfs(struct fsal_obj_ops * ops)154 void lzfs_fsal_handle_ops_pnfs(struct fsal_obj_ops *ops) {
155 ops->layoutget = lzfs_fsal_layoutget;
156 ops->layoutreturn = lzfs_fsal_layoutreturn;
157 ops->layoutcommit = lzfs_fsal_layoutcommit;
158 }
159