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