xref: /linux/fs/ceph/ioctl.c (revision deaec85cd8bad3841412ff8cefec463f2688806b)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/ceph/ceph_debug.h>
3 #include <linux/in.h>
4 
5 #include "super.h"
6 #include "mds_client.h"
7 #include "ioctl.h"
8 #include <linux/ceph/striper.h>
9 #include <linux/fscrypt.h>
10 
11 /*
12  * ioctls
13  */
14 
15 /*
16  * get and set the file layout
17  */
18 static long ceph_ioctl_get_layout(struct file *file, void __user *arg)
19 {
20 	struct ceph_inode_info *ci = ceph_inode(file_inode(file));
21 	struct ceph_ioctl_layout l;
22 	int err;
23 
24 	err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT, false);
25 	if (!err) {
26 		l.stripe_unit = ci->i_layout.stripe_unit;
27 		l.stripe_count = ci->i_layout.stripe_count;
28 		l.object_size = ci->i_layout.object_size;
29 		l.data_pool = ci->i_layout.pool_id;
30 		l.preferred_osd = -1;
31 		if (copy_to_user(arg, &l, sizeof(l)))
32 			return -EFAULT;
33 	}
34 
35 	return err;
36 }
37 
38 static long __validate_layout(struct ceph_mds_client *mdsc,
39 			      struct ceph_ioctl_layout *l)
40 {
41 	int i, err;
42 
43 	/* validate striping parameters */
44 	if ((l->object_size & ~PAGE_MASK) ||
45 	    (l->stripe_unit & ~PAGE_MASK) ||
46 	    ((unsigned)l->stripe_unit != 0 &&
47 	     ((unsigned)l->object_size % (unsigned)l->stripe_unit)))
48 		return -EINVAL;
49 
50 	/* make sure it's a valid data pool */
51 	mutex_lock(&mdsc->mutex);
52 	err = -EINVAL;
53 	for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++)
54 		if (mdsc->mdsmap->m_data_pg_pools[i] == l->data_pool) {
55 			err = 0;
56 			break;
57 		}
58 	mutex_unlock(&mdsc->mutex);
59 	if (err)
60 		return err;
61 
62 	return 0;
63 }
64 
65 static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
66 {
67 	struct inode *inode = file_inode(file);
68 	struct ceph_mds_client *mdsc = ceph_sb_to_fs_client(inode->i_sb)->mdsc;
69 	struct ceph_mds_request *req;
70 	struct ceph_ioctl_layout l;
71 	struct ceph_inode_info *ci = ceph_inode(file_inode(file));
72 	struct ceph_ioctl_layout nl;
73 	int err;
74 
75 	if (!inode_owner_or_capable(&nop_mnt_idmap, inode))
76 		return -EACCES;
77 
78 	if (copy_from_user(&l, arg, sizeof(l)))
79 		return -EFAULT;
80 
81 	/* validate changed params against current layout */
82 	err = ceph_do_getattr(file_inode(file), CEPH_STAT_CAP_LAYOUT, false);
83 	if (err)
84 		return err;
85 
86 	memset(&nl, 0, sizeof(nl));
87 	if (l.stripe_count)
88 		nl.stripe_count = l.stripe_count;
89 	else
90 		nl.stripe_count = ci->i_layout.stripe_count;
91 	if (l.stripe_unit)
92 		nl.stripe_unit = l.stripe_unit;
93 	else
94 		nl.stripe_unit = ci->i_layout.stripe_unit;
95 	if (l.object_size)
96 		nl.object_size = l.object_size;
97 	else
98 		nl.object_size = ci->i_layout.object_size;
99 	if (l.data_pool)
100 		nl.data_pool = l.data_pool;
101 	else
102 		nl.data_pool = ci->i_layout.pool_id;
103 
104 	/* this is obsolete, and always -1 */
105 	nl.preferred_osd = -1;
106 
107 	err = __validate_layout(mdsc, &nl);
108 	if (err)
109 		return err;
110 
111 	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETLAYOUT,
112 				       USE_AUTH_MDS);
113 	if (IS_ERR(req))
114 		return PTR_ERR(req);
115 	req->r_inode = inode;
116 	ihold(inode);
117 	req->r_num_caps = 1;
118 
119 	req->r_inode_drop = CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL;
120 
121 	req->r_args.setlayout.layout.fl_stripe_unit =
122 		cpu_to_le32(l.stripe_unit);
123 	req->r_args.setlayout.layout.fl_stripe_count =
124 		cpu_to_le32(l.stripe_count);
125 	req->r_args.setlayout.layout.fl_object_size =
126 		cpu_to_le32(l.object_size);
127 	req->r_args.setlayout.layout.fl_pg_pool = cpu_to_le32(l.data_pool);
128 
129 	err = ceph_mdsc_do_request(mdsc, NULL, req);
130 	ceph_mdsc_put_request(req);
131 	return err;
132 }
133 
134 /*
135  * Set a layout policy on a directory inode. All items in the tree
136  * rooted at this inode will inherit this layout on creation,
137  * (It doesn't apply retroactively )
138  * unless a subdirectory has its own layout policy.
139  */
140 static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg)
141 {
142 	struct inode *inode = file_inode(file);
143 	struct ceph_mds_request *req;
144 	struct ceph_ioctl_layout l;
145 	int err;
146 	struct ceph_mds_client *mdsc = ceph_sb_to_fs_client(inode->i_sb)->mdsc;
147 
148 	if (!inode_owner_or_capable(&nop_mnt_idmap, inode))
149 		return -EACCES;
150 
151 	/* copy and validate */
152 	if (copy_from_user(&l, arg, sizeof(l)))
153 		return -EFAULT;
154 
155 	err = __validate_layout(mdsc, &l);
156 	if (err)
157 		return err;
158 
159 	req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETDIRLAYOUT,
160 				       USE_AUTH_MDS);
161 
162 	if (IS_ERR(req))
163 		return PTR_ERR(req);
164 	req->r_inode = inode;
165 	ihold(inode);
166 	req->r_num_caps = 1;
167 
168 	req->r_args.setlayout.layout.fl_stripe_unit =
169 			cpu_to_le32(l.stripe_unit);
170 	req->r_args.setlayout.layout.fl_stripe_count =
171 			cpu_to_le32(l.stripe_count);
172 	req->r_args.setlayout.layout.fl_object_size =
173 			cpu_to_le32(l.object_size);
174 	req->r_args.setlayout.layout.fl_pg_pool =
175 			cpu_to_le32(l.data_pool);
176 
177 	err = ceph_mdsc_do_request(mdsc, inode, req);
178 	ceph_mdsc_put_request(req);
179 	return err;
180 }
181 
182 /*
183  * Return object name, size/offset information, and location (OSD
184  * number, network address) for a given file offset.
185  */
186 static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
187 {
188 	struct ceph_ioctl_dataloc dl;
189 	struct inode *inode = file_inode(file);
190 	struct ceph_inode_info *ci = ceph_inode(inode);
191 	struct ceph_osd_client *osdc =
192 		&ceph_sb_to_fs_client(inode->i_sb)->client->osdc;
193 	struct ceph_object_locator oloc;
194 	CEPH_DEFINE_OID_ONSTACK(oid);
195 	u32 xlen;
196 	u64 tmp;
197 	struct ceph_pg pgid;
198 	int r;
199 
200 	/* copy and validate */
201 	if (copy_from_user(&dl, arg, sizeof(dl)))
202 		return -EFAULT;
203 
204 	down_read(&osdc->lock);
205 	ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, 1,
206 				      &dl.object_no, &dl.object_offset, &xlen);
207 	dl.file_offset -= dl.object_offset;
208 	dl.object_size = ci->i_layout.object_size;
209 	dl.block_size = ci->i_layout.stripe_unit;
210 
211 	/* block_offset = object_offset % block_size */
212 	tmp = dl.object_offset;
213 	dl.block_offset = do_div(tmp, dl.block_size);
214 
215 	snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx",
216 		 ceph_ino(inode), dl.object_no);
217 
218 	oloc.pool = ci->i_layout.pool_id;
219 	oloc.pool_ns = ceph_try_get_string(ci->i_layout.pool_ns);
220 	ceph_oid_printf(&oid, "%s", dl.object_name);
221 
222 	r = ceph_object_locator_to_pg(osdc->osdmap, &oid, &oloc, &pgid);
223 
224 	ceph_oloc_destroy(&oloc);
225 	if (r < 0) {
226 		up_read(&osdc->lock);
227 		return r;
228 	}
229 
230 	dl.osd = ceph_pg_to_acting_primary(osdc->osdmap, &pgid);
231 	if (dl.osd >= 0) {
232 		struct ceph_entity_addr *a =
233 			ceph_osd_addr(osdc->osdmap, dl.osd);
234 		if (a)
235 			memcpy(&dl.osd_addr, &a->in_addr, sizeof(dl.osd_addr));
236 	} else {
237 		memset(&dl.osd_addr, 0, sizeof(dl.osd_addr));
238 	}
239 	up_read(&osdc->lock);
240 
241 	/* send result back to user */
242 	if (copy_to_user(arg, &dl, sizeof(dl)))
243 		return -EFAULT;
244 
245 	return 0;
246 }
247 
248 static long ceph_ioctl_lazyio(struct file *file)
249 {
250 	struct ceph_file_info *fi = file->private_data;
251 	struct inode *inode = file_inode(file);
252 	struct ceph_inode_info *ci = ceph_inode(inode);
253 	struct ceph_mds_client *mdsc = ceph_inode_to_fs_client(inode)->mdsc;
254 	struct ceph_client *cl = mdsc->fsc->client;
255 	bool is_file_already_lazy = false;
256 
257 	spin_lock(&ci->i_ceph_lock);
258 	if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) {
259 		fi->fmode |= CEPH_FILE_MODE_LAZY;
260 		ci->i_nr_by_mode[ffs(CEPH_FILE_MODE_LAZY)]++;
261 		__ceph_touch_fmode(ci, mdsc, fi->fmode);
262 	} else {
263 		is_file_already_lazy = true;
264 	}
265 	spin_unlock(&ci->i_ceph_lock);
266 
267 	if (is_file_already_lazy) {
268 		doutc(cl, "file %p %p %llx.%llx already lazy\n", file, inode,
269 		      ceph_vinop(inode));
270 	} else {
271 		doutc(cl, "file %p %p %llx.%llx marked lazy\n", file, inode,
272 		      ceph_vinop(inode));
273 
274 		ceph_check_caps(ci, 0);
275 	}
276 
277 	return 0;
278 }
279 
280 static long ceph_ioctl_syncio(struct file *file)
281 {
282 	struct ceph_file_info *fi = file->private_data;
283 
284 	fi->flags |= CEPH_F_SYNC;
285 	return 0;
286 }
287 
288 static int vet_mds_for_fscrypt(struct file *file)
289 {
290 	int i, ret = -EOPNOTSUPP;
291 	struct ceph_mds_client	*mdsc = ceph_sb_to_mdsc(file_inode(file)->i_sb);
292 
293 	mutex_lock(&mdsc->mutex);
294 	for (i = 0; i < mdsc->max_sessions; i++) {
295 		struct ceph_mds_session *s = mdsc->sessions[i];
296 
297 		if (!s)
298 			continue;
299 		if (test_bit(CEPHFS_FEATURE_ALTERNATE_NAME, &s->s_features))
300 			ret = 0;
301 		break;
302 	}
303 	mutex_unlock(&mdsc->mutex);
304 	return ret;
305 }
306 
307 static long ceph_set_encryption_policy(struct file *file, unsigned long arg)
308 {
309 	int ret, got = 0;
310 	struct inode *inode = file_inode(file);
311 	struct ceph_inode_info *ci = ceph_inode(inode);
312 
313 	/* encrypted directories can't have striped layout */
314 	if (ci->i_layout.stripe_count > 1)
315 		return -EINVAL;
316 
317 	ret = vet_mds_for_fscrypt(file);
318 	if (ret)
319 		return ret;
320 
321 	/*
322 	 * Ensure we hold these caps so that we _know_ that the rstats check
323 	 * in the empty_dir check is reliable.
324 	 */
325 	ret = ceph_get_caps(file, CEPH_CAP_FILE_SHARED, 0, -1, &got);
326 	if (ret)
327 		return ret;
328 
329 	ret = fscrypt_ioctl_set_policy(file, (const void __user *)arg);
330 	if (got)
331 		ceph_put_cap_refs(ci, got);
332 
333 	return ret;
334 }
335 
336 static const char *ceph_ioctl_cmd_name(const unsigned int cmd)
337 {
338 	switch (cmd) {
339 	case CEPH_IOC_GET_LAYOUT:
340 		return "get_layout";
341 	case CEPH_IOC_SET_LAYOUT:
342 		return "set_layout";
343 	case CEPH_IOC_SET_LAYOUT_POLICY:
344 		return "set_layout_policy";
345 	case CEPH_IOC_GET_DATALOC:
346 		return "get_dataloc";
347 	case CEPH_IOC_LAZYIO:
348 		return "lazyio";
349 	case CEPH_IOC_SYNCIO:
350 		return "syncio";
351 	case FS_IOC_SET_ENCRYPTION_POLICY:
352 		return "set_encryption_policy";
353 	case FS_IOC_GET_ENCRYPTION_POLICY:
354 		return "get_encryption_policy";
355 	case FS_IOC_GET_ENCRYPTION_POLICY_EX:
356 		return "get_encryption_policy_ex";
357 	case FS_IOC_ADD_ENCRYPTION_KEY:
358 		return "add_encryption_key";
359 	case FS_IOC_REMOVE_ENCRYPTION_KEY:
360 		return "remove_encryption_key";
361 	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
362 		return "remove_encryption_key_all_users";
363 	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
364 		return "get_encryption_key_status";
365 	case FS_IOC_GET_ENCRYPTION_NONCE:
366 		return "get_encryption_nonce";
367 	default:
368 		return "unknown";
369 	}
370 }
371 
372 long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
373 {
374 	struct inode *inode = file_inode(file);
375 	struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
376 	int ret;
377 
378 	doutc(fsc->client, "file %p %p %llx.%llx cmd %s arg %lu\n", file,
379 	      inode, ceph_vinop(inode), ceph_ioctl_cmd_name(cmd), arg);
380 	switch (cmd) {
381 	case CEPH_IOC_GET_LAYOUT:
382 		return ceph_ioctl_get_layout(file, (void __user *)arg);
383 
384 	case CEPH_IOC_SET_LAYOUT:
385 		return ceph_ioctl_set_layout(file, (void __user *)arg);
386 
387 	case CEPH_IOC_SET_LAYOUT_POLICY:
388 		return ceph_ioctl_set_layout_policy(file, (void __user *)arg);
389 
390 	case CEPH_IOC_GET_DATALOC:
391 		return ceph_ioctl_get_dataloc(file, (void __user *)arg);
392 
393 	case CEPH_IOC_LAZYIO:
394 		return ceph_ioctl_lazyio(file);
395 
396 	case CEPH_IOC_SYNCIO:
397 		return ceph_ioctl_syncio(file);
398 
399 	case FS_IOC_SET_ENCRYPTION_POLICY:
400 		return ceph_set_encryption_policy(file, arg);
401 
402 	case FS_IOC_GET_ENCRYPTION_POLICY:
403 		ret = vet_mds_for_fscrypt(file);
404 		if (ret)
405 			return ret;
406 		return fscrypt_ioctl_get_policy(file, (void __user *)arg);
407 
408 	case FS_IOC_GET_ENCRYPTION_POLICY_EX:
409 		ret = vet_mds_for_fscrypt(file);
410 		if (ret)
411 			return ret;
412 		return fscrypt_ioctl_get_policy_ex(file, (void __user *)arg);
413 
414 	case FS_IOC_ADD_ENCRYPTION_KEY:
415 		ret = vet_mds_for_fscrypt(file);
416 		if (ret)
417 			return ret;
418 		return fscrypt_ioctl_add_key(file, (void __user *)arg);
419 
420 	case FS_IOC_REMOVE_ENCRYPTION_KEY:
421 		return fscrypt_ioctl_remove_key(file, (void __user *)arg);
422 
423 	case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
424 		return fscrypt_ioctl_remove_key_all_users(file,
425 							  (void __user *)arg);
426 
427 	case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
428 		return fscrypt_ioctl_get_key_status(file, (void __user *)arg);
429 
430 	case FS_IOC_GET_ENCRYPTION_NONCE:
431 		ret = vet_mds_for_fscrypt(file);
432 		if (ret)
433 			return ret;
434 		return fscrypt_ioctl_get_nonce(file, (void __user *)arg);
435 	}
436 
437 	return -ENOTTY;
438 }
439